├── .gitignore ├── .images └── Paxos_images.png ├── kpaxos ├── include │ ├── stats.h │ ├── user_stats.h │ ├── kernel_client.h │ ├── kfile.h │ ├── kernel_device.h │ ├── user_eth.h │ └── user_levent.h ├── kproposer.c ├── kacceptor.c ├── kfile.c ├── klearner.c ├── kreplica.c ├── kstats.c ├── user_stats.c ├── user_learner.c ├── user_eth.c ├── user_client.c ├── kernel_device.c ├── kclient.c └── user_levent.c ├── paxos ├── include │ ├── common.h │ ├── storage_utils.h │ ├── quorum.h │ ├── carray.h │ ├── learner.h │ ├── acceptor.h │ ├── storage.h │ ├── proposer.h │ ├── paxos.h │ └── paxos_types.h ├── quorum.c ├── storage_utils.c ├── storage.c ├── carray.c ├── storage_mem.c ├── paxos.c ├── storage_mem-old.c ├── acceptor.c └── learner.c ├── evpaxos ├── include │ ├── eth.h │ ├── evpaxos.h │ ├── paxos_types_pack.h │ ├── evpaxos │ │ ├── config.h │ │ └── paxos.h │ ├── evpaxos_internal.h │ ├── message.h │ └── peers.h ├── evreplica.c ├── eth.c ├── message.c ├── evlearner.c ├── evacceptor.c ├── evproposer.c └── peers.c ├── paxos.conf ├── .clang-format ├── Makefile └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.cmd 2 | *.ko 3 | *.o 4 | .tmp_versions 5 | *.mod.c 6 | *.symvers 7 | *.order 8 | build/** 9 | -------------------------------------------------------------------------------- /.images/Paxos_images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/esposem/Kernel_Paxos/HEAD/.images/Paxos_images.png -------------------------------------------------------------------------------- /kpaxos/include/stats.h: -------------------------------------------------------------------------------- 1 | #ifndef __STATS_H__ 2 | #define __STATS_H__ 3 | 4 | #define STATS_MAX_COUNT 10000000 5 | 6 | void stats_init(void); 7 | void stats_destroy(void); 8 | void stats_add(long latency); 9 | long stats_get_avg(void); 10 | long stats_get_count(void); 11 | void stats_print(void); 12 | void stats_persist(const char* file); 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /kpaxos/include/user_stats.h: -------------------------------------------------------------------------------- 1 | #ifndef USER_STATS 2 | #define USER_STATS 3 | 4 | #include "kernel_client.h" 5 | #include "stats.h" 6 | 7 | #define TIMEOUT_US 1000000 8 | 9 | extern void update_stats(struct stats* stats, struct timeval delivered, 10 | size_t size); 11 | extern void on_stats(struct client* cl); 12 | extern long timeval_diff(struct timeval* t1, struct timeval* t2); 13 | extern void check_timeout(struct client* client); 14 | #endif 15 | -------------------------------------------------------------------------------- /kpaxos/include/kernel_client.h: -------------------------------------------------------------------------------- 1 | #ifndef KERNEL_CLIENT 2 | #define KERNEL_CLIENT 3 | #ifdef user_space 4 | #include 5 | #include 6 | #include 7 | #endif 8 | struct client_value 9 | { 10 | int client_id; 11 | struct timeval t; 12 | size_t size; 13 | char value[0]; 14 | }; 15 | 16 | struct user_msg 17 | { 18 | size_t size; 19 | char value[0]; 20 | }; 21 | 22 | struct stats 23 | { 24 | long min_latency; 25 | long max_latency; 26 | long avg_latency; 27 | int delivered_count; 28 | size_t delivered_bytes; 29 | }; 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /kpaxos/include/kfile.h: -------------------------------------------------------------------------------- 1 | #ifndef K_FILE 2 | #define K_FILE 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // for flags and mode, see http://man7.org/linux/man-pages/man2/open.2.html 10 | 11 | struct file* file_open(const char* path, int flags, int rights); 12 | int file_read(struct file* file, unsigned long long offset, unsigned char* data, 13 | unsigned int size); 14 | int file_write(struct file* file, unsigned long long offset, 15 | unsigned char* data, unsigned int size); 16 | void file_close(struct file* file); 17 | int file_sync(struct file* file); 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /kpaxos/include/kernel_device.h: -------------------------------------------------------------------------------- 1 | #ifndef DEVICE_INCLUDE 2 | #define DEVICE_INCLUDE 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | extern int kdev_open(struct inode*, struct file*); 10 | extern int kdev_release(struct inode*, struct file*); 11 | extern ssize_t kdev_read(struct file*, char*, size_t, loff_t*); 12 | extern ssize_t kdev_write(struct file*, const char*, size_t, loff_t*); 13 | extern int kdevchar_init(int id, char* name); 14 | extern unsigned int kdev_poll(struct file*, poll_table* wait); 15 | extern void kdevchar_exit(void); 16 | extern void kset_message(char* msg, size_t size); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /paxos/include/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_PAX 2 | #define COMMON_PAX 3 | 4 | #include //kmalloc 5 | 6 | #define pmalloc(size) kmalloc(size, GFP_ATOMIC) 7 | #define prealloc(ptr, size) krealloc(ptr, size, GFP_ATOMIC) 8 | #define pfree(ptr) kfree(ptr) 9 | 10 | extern const char* MOD_NAME; 11 | 12 | typedef uint8_t eth_address; 13 | 14 | #define LOG_DEBUG(fmt, args...) \ 15 | printk(KERN_DEBUG "%s: " fmt "\n", MOD_NAME, ##args) 16 | #define LOG_INFO(fmt, args...) \ 17 | printk(KERN_INFO "%s: " fmt "\n", MOD_NAME, ##args) 18 | #define LOG_ERROR(fmt, args...) \ 19 | printk(KERN_ERR "%s: " fmt "\n", MOD_NAME, ##args) 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /kpaxos/include/user_eth.h: -------------------------------------------------------------------------------- 1 | #ifndef USER_ETH 2 | #define USER_ETH 3 | 4 | #include "kernel_client.h" 5 | #include "user_levent.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | extern void eth_sendmsg(struct eth_connection* ethop, 12 | uint8_t dest_addr[ETH_ALEN], void* clv, size_t size); 13 | extern int eth_init(struct eth_connection* ethop); 14 | extern int eth_listen(struct eth_connection* ethop); 15 | extern size_t eth_recmsg(struct eth_connection* ethop, 16 | uint8_t sndr_addr[ETH_ALEN], char* rmsg, size_t len); 17 | extern int str_to_mac(const char* str, uint8_t daddr[ETH_ALEN]); 18 | extern int mac_to_str(uint8_t daddr[ETH_ALEN], char* str); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /evpaxos/include/eth.h: -------------------------------------------------------------------------------- 1 | #ifndef __ETH_H__ 2 | #define __ETH_H__ 3 | 4 | #include "peers.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // typedef void (*rcv_cb)(struct net_device* dev, uint8_t src_addr[ETH_ALEN], 11 | // char* rmsg, size_t len); 12 | int eth_subscribe(struct net_device* dev, uint16_t proto, peer_cb cb, 13 | void* arg); 14 | 15 | struct net_device* eth_init(const char* if_name); 16 | int eth_listen(struct net_device* dev); 17 | int eth_send(struct net_device* dev, uint8_t dest_addr[ETH_ALEN], 18 | uint16_t proto, const char* msg, size_t len); 19 | int eth_destroy(struct net_device* dev); 20 | int str_to_mac(const char* str, uint8_t daddr[ETH_ALEN]); 21 | int mac_to_str(uint8_t daddr[ETH_ALEN], char* str); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /paxos.conf: -------------------------------------------------------------------------------- 1 | ## Kernel_Paxos configuration file 2 | # important! Every line starting OR containig # will be discarded. 3 | 4 | # Specify an id and MAC address for each acceptor/proposer/replica. 5 | # Ids must start from 0 and must be unique. 6 | 7 | # replica 0 00:00:00:00:00:00 8 | # replica 1 00:00:00:00:00:00 9 | # replica 2 00:00:00:00:00:00 10 | 11 | # Alternatively it is possible to specify acceptors and proposers separately. 12 | acceptor 0 00:00:00:00:00:00 13 | acceptor 1 00:00:00:00:00:00 14 | acceptor 2 00:00:00:00:00:00 15 | proposer 0 00:00:00:00:00:00 16 | 17 | # Verbosity level: must be one of quiet, error, info, or debug. 18 | # Default is 'error'. 19 | # verbosity info 20 | 21 | ################################### Learners ################################## 22 | 23 | # Should learners start from instance 0 when starting up? 24 | # Default is 'no'. 25 | # learner-catch-up yes 26 | 27 | ################################## Proposers ################################## 28 | 29 | # How many seconds should pass before a proposer times out an instance? 30 | # Default is 1. 31 | # proposer-timeout 10 32 | 33 | # How many phase 1 instances should proposers preexecute? 34 | # Default is 128. 35 | # proposer-preexec-window 1024 36 | -------------------------------------------------------------------------------- /kpaxos/kproposer.c: -------------------------------------------------------------------------------- 1 | #include "evpaxos.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | const char* MOD_NAME = "KProposer"; 11 | 12 | static char* if_name = "enp4s0"; 13 | module_param(if_name, charp, 0000); 14 | MODULE_PARM_DESC(if_name, "The interface name, default enp4s0"); 15 | 16 | static int id = 0; 17 | module_param(id, int, S_IRUGO); 18 | MODULE_PARM_DESC(id, "The proposer id, default 0"); 19 | 20 | static char* path = "./paxos.conf"; 21 | module_param(path, charp, S_IRUGO); 22 | MODULE_PARM_DESC(path, "The config file position, default ./paxos.conf"); 23 | 24 | static struct evproposer* prop = NULL; 25 | 26 | static void 27 | start_proposer(int id) 28 | { 29 | prop = evproposer_init(id, if_name, path); 30 | if (prop == NULL) { 31 | LOG_ERROR("Could not start the proposer"); 32 | } 33 | } 34 | 35 | static int __init 36 | init_prop(void) 37 | { 38 | start_proposer(id); 39 | LOG_INFO("Module loaded"); 40 | return 0; 41 | } 42 | 43 | static void __exit 44 | prop_exit(void) 45 | { 46 | if (prop != NULL) 47 | evproposer_free(prop); 48 | LOG_INFO("Module unloaded"); 49 | } 50 | 51 | module_init(init_prop); 52 | module_exit(prop_exit); 53 | MODULE_LICENSE("GPL"); 54 | MODULE_AUTHOR("Emanuele Giuseppe Esposito"); 55 | -------------------------------------------------------------------------------- /kpaxos/kacceptor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "evpaxos.h" 10 | 11 | const char* MOD_NAME = "KAcceptor"; 12 | 13 | static char* if_name = "enp4s0"; 14 | module_param(if_name, charp, 0000); 15 | MODULE_PARM_DESC(if_name, "The interface name, default enp4s0"); 16 | 17 | static int id = 0; 18 | module_param(id, int, S_IRUGO); 19 | MODULE_PARM_DESC(id, "The acceptor id, default 0"); 20 | 21 | static char* path = "./paxos.conf"; 22 | module_param(path, charp, S_IRUGO); 23 | MODULE_PARM_DESC(path, "The config file position, default ./paxos.conf"); 24 | 25 | static struct evacceptor* acc = NULL; 26 | 27 | static void 28 | start_acceptor(int id) 29 | { 30 | acc = evacceptor_init(id, if_name, path); 31 | if (acc == NULL) { 32 | LOG_ERROR("Could not start the acceptor\n"); 33 | } 34 | } 35 | 36 | static int __init 37 | init_acceptor(void) 38 | { 39 | start_acceptor(id); 40 | LOG_INFO("Module loaded"); 41 | return 0; 42 | } 43 | 44 | static void __exit 45 | acceptor_exit(void) 46 | { 47 | if (acc != NULL) 48 | evacceptor_free(acc); 49 | LOG_INFO("Module unloaded"); 50 | } 51 | 52 | module_init(init_acceptor) module_exit(acceptor_exit) MODULE_LICENSE("GPL"); 53 | MODULE_AUTHOR("Emanuele Giuseppe Esposito"); 54 | -------------------------------------------------------------------------------- /kpaxos/kfile.c: -------------------------------------------------------------------------------- 1 | #include "kfile.h" 2 | 3 | // Taken from 4 | // https://stackoverflow.com/questions/1184274/how-to-read-write-files-within-a-linux-kernel-module 5 | 6 | struct file* 7 | file_open(const char* path, int flags, int rights) 8 | { 9 | struct file* filp = NULL; 10 | mm_segment_t oldfs; 11 | int err = 0; 12 | 13 | oldfs = get_fs(); 14 | set_fs(get_ds()); 15 | filp = filp_open(path, flags, rights); 16 | set_fs(oldfs); 17 | if (IS_ERR(filp)) { 18 | err = PTR_ERR(filp); 19 | printk(KERN_ERR "File Error %d\n", err); 20 | return NULL; 21 | } 22 | return filp; 23 | } 24 | 25 | void 26 | file_close(struct file* file) 27 | { 28 | if (file) 29 | filp_close(file, NULL); 30 | } 31 | 32 | int 33 | file_read(struct file* file, unsigned long long offset, unsigned char* data, 34 | unsigned int size) 35 | { 36 | mm_segment_t oldfs; 37 | int ret; 38 | 39 | oldfs = get_fs(); 40 | set_fs(get_ds()); 41 | 42 | ret = vfs_read(file, data, size, &offset); 43 | 44 | set_fs(oldfs); 45 | return ret; 46 | } 47 | 48 | int 49 | file_write(struct file* file, unsigned long long offset, unsigned char* data, 50 | unsigned int size) 51 | { 52 | mm_segment_t oldfs; 53 | int ret; 54 | 55 | oldfs = get_fs(); 56 | set_fs(get_ds()); 57 | 58 | ret = vfs_write(file, data, size, &offset); 59 | 60 | set_fs(oldfs); 61 | return ret; 62 | } 63 | 64 | int 65 | file_sync(struct file* file) 66 | { 67 | vfs_fsync(file, 0); 68 | return 0; 69 | } 70 | -------------------------------------------------------------------------------- /evpaxos/include/evpaxos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "evpaxos/paxos.h" 29 | #include "evpaxos/config.h" 30 | -------------------------------------------------------------------------------- /kpaxos/klearner.c: -------------------------------------------------------------------------------- 1 | #include "evpaxos.h" 2 | #include "kernel_device.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | const char* MOD_NAME = "KLearner"; 11 | 12 | static int id = 0; 13 | module_param(id, int, S_IRUGO); 14 | MODULE_PARM_DESC(id, "The learner id (used for kdevice), default 0"); 15 | 16 | static char* if_name = "enp4s0"; 17 | module_param(if_name, charp, 0000); 18 | MODULE_PARM_DESC(if_name, "The interface name, default enp4s0"); 19 | 20 | static char* path = "./paxos.conf"; 21 | module_param(path, charp, S_IRUGO); 22 | MODULE_PARM_DESC(path, "The config file position, default ./paxos.conf"); 23 | 24 | static struct evlearner* lea = NULL; 25 | 26 | static void 27 | on_deliver(unsigned int iid, char* value, size_t size, void* arg) 28 | { 29 | kset_message(value, size); 30 | } 31 | 32 | static int 33 | start_learner(void) 34 | { 35 | kdevchar_init(id, "klearner"); 36 | lea = evlearner_init(on_deliver, NULL, if_name, path, 0); 37 | 38 | if (lea == NULL) { 39 | LOG_ERROR("Could not start the learner!"); 40 | } 41 | 42 | return 0; 43 | } 44 | 45 | static int __init 46 | init_learner(void) 47 | { 48 | if (id < 0 || id > 10) { 49 | LOG_ERROR("you must give an id!"); 50 | return 0; 51 | } 52 | start_learner(); 53 | LOG_INFO("Module loaded"); 54 | return 0; 55 | } 56 | 57 | static void __exit 58 | learner_exit(void) 59 | { 60 | kdevchar_exit(); 61 | if (lea != NULL) 62 | evlearner_free(lea); 63 | LOG_INFO("Module unloaded"); 64 | } 65 | 66 | module_init(init_learner); 67 | module_exit(learner_exit); 68 | MODULE_LICENSE("GPL"); 69 | MODULE_AUTHOR("Emanuele Giuseppe Esposito"); 70 | -------------------------------------------------------------------------------- /kpaxos/kreplica.c: -------------------------------------------------------------------------------- 1 | #include "evpaxos.h" 2 | #include "kernel_device.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | const char* MOD_NAME = "KReplica"; 12 | 13 | static int id = 0; 14 | module_param(id, int, S_IRUGO); 15 | MODULE_PARM_DESC(id, "The replica id, default 0"); 16 | 17 | static char* if_name = "enp4s0"; 18 | module_param(if_name, charp, 0000); 19 | MODULE_PARM_DESC(if_name, "The interface name, default enp4s0"); 20 | 21 | static char* path = "./paxos.conf"; 22 | module_param(path, charp, S_IRUGO); 23 | MODULE_PARM_DESC(path, "The config file position, default ./paxos.conf"); 24 | 25 | static struct evpaxos_replica* replica = NULL; 26 | 27 | void 28 | deliver(unsigned iid, char* value, size_t size, void* arg) 29 | { 30 | kset_message(value, size); 31 | } 32 | 33 | static void 34 | start_replica(int id) 35 | { 36 | kdevchar_init(id, "klearner"); 37 | replica = evpaxos_replica_init(id, deliver, NULL, if_name, path); 38 | 39 | if (replica == NULL) { 40 | LOG_ERROR("Could not start the replica!"); 41 | } 42 | } 43 | 44 | static int __init 45 | init_replica(void) 46 | { 47 | if (id < 0) { 48 | LOG_ERROR("you must give a valid id!"); 49 | return 0; 50 | } 51 | start_replica(id); 52 | LOG_INFO("Module loaded"); 53 | return 0; 54 | } 55 | 56 | static void __exit 57 | replica_exit(void) 58 | { 59 | kdevchar_exit(); 60 | if (replica != NULL) 61 | evpaxos_replica_free(replica); 62 | LOG_INFO("Module unloaded"); 63 | } 64 | 65 | module_init(init_replica); 66 | module_exit(replica_exit); 67 | MODULE_LICENSE("GPL"); 68 | MODULE_AUTHOR("Emanuele Giuseppe Esposito"); 69 | -------------------------------------------------------------------------------- /paxos/include/storage_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _STORAGE_UTILS_H_ 29 | #define _STORAGE_UTILS_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | #include "paxos.h" 37 | 38 | char* paxos_accepted_to_buffer(paxos_accepted* acc); 39 | void paxos_accepted_from_buffer(char* buffer, paxos_accepted* out); 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /paxos/include/quorum.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _QUORUM_H_ 29 | #define _QUORUM_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | struct quorum 37 | { 38 | int count; 39 | int quorum; 40 | int acceptors; 41 | int* acceptor_ids; 42 | }; 43 | 44 | void quorum_init(struct quorum* q, int acceptors); 45 | void quorum_clear(struct quorum* q); 46 | void quorum_destroy(struct quorum* q); 47 | int quorum_add(struct quorum* q, int id); 48 | int quorum_reached(struct quorum* q); 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /evpaxos/include/paxos_types_pack.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _PAXOS_TYPES_PACK_H_ 29 | #define _PAXOS_TYPES_PACK_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | #include "common.h" 37 | #include "paxos_types.h" 38 | 39 | long msgpack_pack_paxos_message(msgpack_packer* p, paxos_message* v); 40 | int msgpack_unpack_paxos_message(paxos_message* msg, char* msg_data, 41 | paxos_message_type proto, 42 | msgpack_packer* recv_data, int size); 43 | 44 | #ifdef __cplusplus 45 | } 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /paxos/include/carray.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _CARRAY_H_ 29 | #define _CARRAY_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | #include "common.h" 36 | 37 | struct carray; 38 | 39 | struct carray* carray_new(int size); 40 | void carray_free(struct carray* a); 41 | int carray_empty(struct carray* a); 42 | int carray_size(struct carray* a); 43 | int carray_push_back(struct carray* a, void* p); 44 | void carray_foreach(struct carray* a, void (*carray_cb)(void*)); 45 | void* carray_pop_front(struct carray* a); 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /paxos/include/learner.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _LEARNER_H_ 29 | #define _LEARNER_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | #include "paxos.h" 37 | 38 | struct learner; 39 | 40 | struct learner* learner_new(int acceptors); 41 | void learner_free(struct learner* l); 42 | void learner_set_instance_id(struct learner* l, iid_t iid); 43 | void trim_old_learn(struct learner* l, iid_t iid); 44 | void learner_receive_accepted(struct learner* l, paxos_accepted* ack); 45 | int learner_deliver_next(struct learner* l, paxos_accepted* out); 46 | int learner_has_holes(struct learner* l, iid_t* from, iid_t* to); 47 | 48 | #ifdef __cplusplus 49 | } 50 | #endif 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /kpaxos/kstats.c: -------------------------------------------------------------------------------- 1 | #include "common.h" 2 | #include "kfile.h" 3 | #include "paxos.h" 4 | #include "stats.h" 5 | #include 6 | #include 7 | #include 8 | 9 | static long* a = 0; // absolute time 10 | static long* e = 0; // elapsed time between calls to stats_add 11 | static unsigned long count; 12 | static struct timeval then; 13 | 14 | void 15 | stats_init() 16 | { 17 | e = vmalloc(STATS_MAX_COUNT * sizeof(long)); 18 | memset(e, 0, STATS_MAX_COUNT * sizeof(long)); 19 | a = vmalloc(STATS_MAX_COUNT * sizeof(long)); 20 | memset(a, 0, STATS_MAX_COUNT * sizeof(long)); 21 | count = 0; 22 | do_gettimeofday(&then); 23 | } 24 | 25 | void 26 | stats_destroy() 27 | { 28 | count = 0; 29 | if (a) 30 | vfree(a); 31 | if (e) 32 | vfree(e); 33 | } 34 | 35 | void 36 | stats_add(long latency) 37 | { 38 | struct timeval now; 39 | long us; 40 | 41 | if (count == STATS_MAX_COUNT) { 42 | paxos_log_error("Stats error: array is full"); 43 | return; 44 | } 45 | 46 | do_gettimeofday(&now); 47 | us = (now.tv_sec - then.tv_sec) * 1000000; 48 | if (us < 0) 49 | us = 0; 50 | 51 | us += (now.tv_usec - then.tv_usec); 52 | a[count] = us; 53 | e[count++] = latency; 54 | then = now; 55 | } 56 | 57 | long 58 | stats_get_avg() 59 | { 60 | int i; 61 | long avg = 0; 62 | 63 | for (i = 0; i < count; ++i) 64 | avg += (e[i] - avg) / (i + 1); 65 | 66 | return avg; 67 | } 68 | 69 | long 70 | stats_get_count() 71 | { 72 | return count; 73 | } 74 | 75 | void 76 | stats_print() 77 | { 78 | LOG_INFO("Statistics with %d entries average of %ld us", count, 79 | stats_get_avg()); 80 | } 81 | 82 | void 83 | stats_persist(const char* file) 84 | { 85 | int i; 86 | long abs = 0; 87 | unsigned long long offset = 0; 88 | struct file* f = file_open(file, O_CREAT | O_WRONLY | O_TRUNC, 00666); 89 | char line[128]; 90 | 91 | if (f) { 92 | sprintf(line, "#ORDER\tLATENCY\tABS\n"); 93 | offset += file_write(f, offset, line, strlen(line)); 94 | for (i = 0; i < count; i++) { 95 | abs += a[i]; 96 | sprintf(line, "%d\t%ld\t%ld\n", (i + 1), e[i], abs); 97 | offset += file_write(f, offset, line, strlen(line)); 98 | } 99 | file_sync(f); 100 | file_close(f); 101 | } else { 102 | paxos_log_error("Stats: could not save statistics to file '%s'", file); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /paxos/quorum.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "quorum.h" 29 | #include "paxos.h" 30 | #include 31 | 32 | void 33 | quorum_init(struct quorum* q, int acceptors) 34 | { 35 | q->acceptors = acceptors; 36 | q->quorum = paxos_quorum(acceptors); 37 | q->acceptor_ids = pmalloc(sizeof(int) * q->acceptors); 38 | quorum_clear(q); 39 | } 40 | 41 | void 42 | quorum_clear(struct quorum* q) 43 | { 44 | q->count = 0; 45 | memset(q->acceptor_ids, 0, sizeof(int) * q->acceptors); 46 | } 47 | 48 | void 49 | quorum_destroy(struct quorum* q) 50 | { 51 | pfree(q->acceptor_ids); 52 | } 53 | 54 | int 55 | quorum_add(struct quorum* q, int id) 56 | { 57 | if (q->acceptor_ids[id] == 0) { 58 | q->count++; 59 | q->acceptor_ids[id] = 1; 60 | return 1; 61 | } 62 | return 0; 63 | } 64 | 65 | int 66 | quorum_reached(struct quorum* q) 67 | { 68 | return (q->count >= q->quorum); 69 | } 70 | -------------------------------------------------------------------------------- /paxos/storage_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "storage_utils.h" 29 | #include 30 | 31 | char* 32 | paxos_accepted_to_buffer(paxos_accepted* acc) 33 | { 34 | size_t len = acc->value.paxos_value_len; 35 | char* buffer = pmalloc(sizeof(paxos_accepted) + len); 36 | if (buffer == NULL) 37 | return NULL; 38 | memcpy(buffer, acc, sizeof(paxos_accepted)); 39 | if (len > 0) { 40 | memcpy(&buffer[sizeof(paxos_accepted)], acc->value.paxos_value_val, len); 41 | } 42 | return buffer; 43 | } 44 | 45 | void 46 | paxos_accepted_from_buffer(char* buffer, paxos_accepted* out) 47 | { 48 | memcpy(out, buffer, sizeof(paxos_accepted)); 49 | if (out->value.paxos_value_len > 0) { 50 | out->value.paxos_value_val = pmalloc(out->value.paxos_value_len); 51 | memcpy(out->value.paxos_value_val, &buffer[sizeof(paxos_accepted)], 52 | out->value.paxos_value_len); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /evpaxos/include/evpaxos/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _CONFIG_READER_H_ 29 | #define _CONFIG_READER_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | #include "common.h" 37 | 38 | struct evpaxos_config; 39 | 40 | struct evpaxos_config* evpaxos_config_read(char* name); 41 | void evpaxos_config_free(struct evpaxos_config* config); 42 | eth_address* evpaxos_proposer_address(struct evpaxos_config* c, int i); 43 | int evpaxos_proposer_listen_port(struct evpaxos_config* c, int i); 44 | int evpaxos_acceptor_count(struct evpaxos_config* config); 45 | int evpaxos_proposer_count(struct evpaxos_config* config); 46 | eth_address* evpaxos_acceptor_address(struct evpaxos_config* c, int i); 47 | int evpaxos_acceptor_listen_port(struct evpaxos_config* c, int i); 48 | 49 | #ifdef __cplusplus 50 | } 51 | #endif 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /paxos/include/acceptor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _ACCEPTOR_H_ 29 | #define _ACCEPTOR_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | #include "paxos.h" 37 | 38 | struct acceptor; 39 | 40 | struct acceptor* acceptor_new(int id); 41 | void acceptor_free(struct acceptor* a); 42 | int acceptor_receive_prepare(struct acceptor* a, paxos_prepare* req, 43 | paxos_message* out); 44 | int acceptor_receive_accept(struct acceptor* a, paxos_accept* req, 45 | paxos_message* out); 46 | int acceptor_receive_repeat(struct acceptor* a, iid_t iid, 47 | paxos_accepted* out); 48 | int acceptor_receive_trim(struct acceptor* a, paxos_trim* trim); 49 | void acceptor_set_current_state(struct acceptor* a, 50 | paxos_acceptor_state* out); 51 | 52 | #ifdef __cplusplus 53 | } 54 | #endif 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /evpaxos/include/evpaxos_internal.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _EVPAXOS_INTERNAL_H_ 29 | #define _EVPAXOS_INTERNAL_H_ 30 | 31 | #include "evpaxos.h" 32 | #include "peers.h" 33 | 34 | struct evlearner* evlearner_init_internal(struct evpaxos_config* config, 35 | struct peers* peers, 36 | deliver_function f, void* arg); 37 | 38 | void evlearner_free_internal(struct evlearner* l); 39 | 40 | struct evacceptor* evacceptor_init_internal(int id, 41 | struct evpaxos_config* config, 42 | struct peers* peers); 43 | 44 | void evacceptor_free_internal(struct evacceptor* a); 45 | 46 | struct evproposer* evproposer_init_internal(int id, 47 | struct evpaxos_config* config, 48 | struct peers* peers); 49 | 50 | void evproposer_free_internal(struct evproposer* p); 51 | 52 | struct net_device* evlearner_get_device(struct evlearner* ev); 53 | 54 | void evlearner_send_hi(struct peers* p); 55 | void evproposer_preexec_once(struct evproposer* arg); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /kpaxos/include/user_levent.h: -------------------------------------------------------------------------------- 1 | #ifndef USER_CLIENT 2 | #define USER_CLIENT 3 | 4 | #include "kernel_client.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | enum user_communication 13 | { 14 | OPEN_CONN = 100, 15 | OK, 16 | CLOSE_CONN 17 | }; 18 | 19 | // Common structs 20 | struct chardevice 21 | { 22 | int fd; 23 | int char_device_id; 24 | }; 25 | 26 | struct eth_connection 27 | { 28 | int socket; 29 | char rec_buffer[ETH_DATA_LEN]; 30 | char* if_name; 31 | }; 32 | 33 | // Server side 34 | 35 | struct connection 36 | { 37 | int id; 38 | int start_id; 39 | int end_id; 40 | uint8_t address[ETH_ALEN]; 41 | struct connection* next; 42 | }; 43 | 44 | struct server 45 | { 46 | struct connection_list* connections; // client we accepted connections from 47 | struct chardevice fileop; // File op 48 | struct eth_connection ethop; // ETH op 49 | }; 50 | 51 | // client side 52 | struct client 53 | { 54 | int id; 55 | int value_size; 56 | int outstanding; 57 | int nclients; 58 | struct timeval* nclients_time; 59 | struct stats stats; /* Statistics */ 60 | struct timeval stats_interval; 61 | struct client_value* val; // refers to the send_buffer 62 | char send_buffer[ETH_DATA_LEN]; 63 | int send_buffer_len; 64 | int learner_id; 65 | struct chardevice fileop; // File op 66 | struct eth_connection ethop; // ETH op 67 | uint8_t prop_addr[ETH_ALEN]; 68 | int prop_id; 69 | uint8_t learner_addr[ETH_ALEN]; 70 | }; 71 | 72 | extern int open_file(struct chardevice* c); 73 | extern void write_file(int fd, void* data, size_t size); 74 | extern void usage(const char* name, int client); 75 | 76 | extern struct server* server_new(); 77 | extern int add_connection(struct server* serv, int start, int end, 78 | uint8_t address[ETH_ALEN]); 79 | extern struct connection* find_connection(struct server* serv, int val); 80 | extern void rem_connection(struct server* serv, int id); 81 | extern void new_connection_list(struct server* serv); 82 | extern void print_all_conn(struct server* serv); 83 | extern void server_free(struct server* c); 84 | extern struct server* server_new(); 85 | 86 | extern struct client* client_new(); 87 | extern void prepare_clval(struct client* cl); 88 | extern void print_settings(struct client* cl); 89 | extern void client_free(struct client* cl); 90 | extern void client_submit_value(struct client* cl, int id); 91 | extern int find_proposer(struct client* cl, char* path); 92 | #endif 93 | -------------------------------------------------------------------------------- /paxos/storage.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "storage.h" 29 | 30 | void 31 | storage_init(struct storage* store, int acceptor_id) 32 | { 33 | storage_init_mem(store, acceptor_id); 34 | } 35 | 36 | int 37 | storage_open(struct storage* store) 38 | { 39 | return store->api.open(store->handle); 40 | } 41 | 42 | void 43 | storage_close(struct storage* store) 44 | { 45 | store->api.close(store->handle); 46 | } 47 | 48 | int 49 | storage_tx_begin(struct storage* store) 50 | { 51 | return store->api.tx_begin(store->handle); 52 | } 53 | 54 | int 55 | storage_tx_commit(struct storage* store) 56 | { 57 | return store->api.tx_commit(store->handle); 58 | } 59 | 60 | void 61 | storage_tx_abort(struct storage* store) 62 | { 63 | store->api.tx_abort(store->handle); 64 | } 65 | 66 | int 67 | storage_get_record(struct storage* store, iid_t iid, paxos_accepted* out) 68 | { 69 | return store->api.get(store->handle, iid, out); 70 | } 71 | 72 | int 73 | storage_put_record(struct storage* store, paxos_accepted* acc) 74 | { 75 | return store->api.put(store->handle, acc); 76 | } 77 | 78 | int 79 | storage_trim(struct storage* store, iid_t iid) 80 | { 81 | return store->api.trim(store->handle, iid); 82 | } 83 | 84 | iid_t 85 | storage_get_trim_instance(struct storage* store) 86 | { 87 | return store->api.get_trim_instance(store->handle); 88 | } 89 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: Mozilla 4 | AccessModifierOffset: -2 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: true 8 | AlignEscapedNewlinesLeft: false 9 | AlignOperands: true 10 | AlignTrailingComments: true 11 | AllowAllParametersOfDeclarationOnNextLine: false 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: Inline 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: TopLevel 18 | AlwaysBreakAfterReturnType: TopLevelDefinitions 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: true 22 | BinPackParameters: true 23 | BraceWrapping: 24 | AfterClass: true 25 | AfterControlStatement: false 26 | AfterEnum: true 27 | AfterFunction: true 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: true 31 | AfterUnion: true 32 | BeforeCatch: false 33 | BeforeElse: false 34 | IndentBraces: false 35 | BreakBeforeBinaryOperators: None 36 | BreakBeforeBraces: Mozilla 37 | BreakBeforeTernaryOperators: true 38 | BreakConstructorInitializersBeforeComma: true 39 | ColumnLimit: 80 40 | CommentPragmas: '^ IWYU pragma:' 41 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 42 | ConstructorInitializerIndentWidth: 2 43 | ContinuationIndentWidth: 2 44 | Cpp11BracedListStyle: false 45 | DerivePointerAlignment: false 46 | DisableFormat: false 47 | ExperimentalAutoDetectBinPacking: false 48 | ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 49 | IncludeCategories: 50 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 51 | Priority: 2 52 | - Regex: '^(<|"(gtest|isl|json)/)' 53 | Priority: 3 54 | - Regex: '.*' 55 | Priority: 1 56 | IndentCaseLabels: true 57 | IndentWidth: 2 58 | IndentWrappedFunctionNames: false 59 | KeepEmptyLinesAtTheStartOfBlocks: true 60 | MacroBlockBegin: '' 61 | MacroBlockEnd: '' 62 | MaxEmptyLinesToKeep: 1 63 | NamespaceIndentation: None 64 | ObjCBlockIndentWidth: 2 65 | ObjCSpaceAfterProperty: true 66 | ObjCSpaceBeforeProtocolList: false 67 | PenaltyBreakBeforeFirstCallParameter: 19 68 | PenaltyBreakComment: 300 69 | PenaltyBreakFirstLessLess: 120 70 | PenaltyBreakString: 1000 71 | PenaltyExcessCharacter: 1000000 72 | PenaltyReturnTypeOnItsOwnLine: 200 73 | PointerAlignment: Left 74 | ReflowComments: true 75 | SortIncludes: true 76 | SpaceAfterCStyleCast: false 77 | SpaceBeforeAssignmentOperators: true 78 | SpaceBeforeParens: ControlStatements 79 | SpaceInEmptyParentheses: false 80 | SpacesBeforeTrailingComments: 1 81 | SpacesInAngles: false 82 | SpacesInContainerLiterals: true 83 | SpacesInCStyleCastParentheses: false 84 | SpacesInParentheses: false 85 | SpacesInSquareBrackets: false 86 | Standard: Cpp11 87 | TabWidth: 4 88 | UseTab: Never 89 | ... 90 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PAX_OBJ= \ 2 | paxos/carray.o \ 3 | paxos/paxos.o \ 4 | paxos/quorum.o \ 5 | paxos/storage_mem.o \ 6 | paxos/storage_utils.o \ 7 | paxos/storage.o \ 8 | evpaxos/message.o \ 9 | evpaxos/paxos_types_pack.o \ 10 | evpaxos/config.o \ 11 | evpaxos/peers.o \ 12 | evpaxos/eth.o \ 13 | kpaxos/kfile.o 14 | 15 | CL_OBJ= \ 16 | kpaxos/kclient.o \ 17 | kpaxos/kstats.o \ 18 | evpaxos/evlearner.o \ 19 | paxos/learner.o \ 20 | $(PAX_OBJ) 21 | 22 | PROP_OBJ= \ 23 | kpaxos/kproposer.o \ 24 | evpaxos/evproposer.o \ 25 | paxos/proposer.o \ 26 | $(PAX_OBJ) 27 | 28 | ACC_OBJ= \ 29 | kpaxos/kacceptor.o \ 30 | evpaxos/evacceptor.o \ 31 | paxos/acceptor.o \ 32 | $(PAX_OBJ) 33 | 34 | LEARN_OBJ= \ 35 | kpaxos/klearner.o \ 36 | evpaxos/evlearner.o \ 37 | paxos/learner.o \ 38 | kpaxos/kernel_device.o \ 39 | $(PAX_OBJ) 40 | 41 | REP_OBJ= \ 42 | kpaxos/kernel_device.o \ 43 | kpaxos/kreplica.o \ 44 | evpaxos/evlearner.o \ 45 | evpaxos/evproposer.o \ 46 | evpaxos/evacceptor.o \ 47 | paxos/acceptor.o \ 48 | paxos/learner.o \ 49 | paxos/proposer.o \ 50 | evpaxos/evreplica.o \ 51 | $(PAX_OBJ) 52 | 53 | ################# MODIFY HERE FOR MORE MODULES ############## 54 | obj-m += \ 55 | kproposer.o \ 56 | klearner.o \ 57 | kacceptor.o \ 58 | kreplica.o \ 59 | kclient.o 60 | 61 | kclient-y:= $(CL_OBJ) 62 | kproposer-y:= $(PROP_OBJ) 63 | kacceptor-y:= $(ACC_OBJ) 64 | klearner-y:= $(LEARN_OBJ) 65 | kreplica-y:= $(REP_OBJ) 66 | 67 | ############################################################## 68 | 69 | KDIR ?= /lib/modules/$(shell uname -r)/build 70 | BUILD_DIR ?= $(PWD)/build 71 | BUILD_DIR_MAKEFILE ?= $(PWD)/build/Makefile 72 | 73 | C_COMP:= -std=c99 74 | G_COMP:= -std=gnu99 75 | USR_FLAGS:= -Wall -D user_space 76 | USR_SRCS := $(wildcard kpaxos/user_*.c) 77 | USR_CL := $(filter-out kpaxos/user_learner.c, $(USR_SRCS)) 78 | USR_LEARN := $(filter-out kpaxos/user_client.c, $(USR_SRCS)) 79 | USRC_OBJS := $(patsubst kpaxos/%.c, $(BUILD_DIR)/%.o, $(USR_CL)) 80 | USRL_OBJS := $(patsubst kpaxos/%.c, $(BUILD_DIR)/%.o, $(USR_LEARN)) 81 | 82 | EXTRA_CFLAGS:= -I$(PWD)/kpaxos/include -I$(PWD)/paxos/include -I$(PWD)/evpaxos/include -I$(HOME)/local/include 83 | ccflags-y:= $(G_COMP) -Wall -Wno-declaration-after-statement -Wframe-larger-than=3100 -O3 84 | 85 | all: $(BUILD_DIR) kernel_app user_client user_learner 86 | 87 | kernel_app: $(BUILD_DIR_MAKEFILE) 88 | make -C $(KDIR) M=$(BUILD_DIR) src=$(PWD) modules 89 | 90 | $(BUILD_DIR): 91 | mkdir -p "$@/paxos" 92 | mkdir -p "$@/evpaxos" 93 | mkdir -p "$@/kpaxos" 94 | 95 | $(BUILD_DIR_MAKEFILE): $(BUILD_DIR) 96 | touch "$@" 97 | 98 | $(BUILD_DIR)/%.o: kpaxos/%.c 99 | $(CC) $(G_COMP) $(USR_FLAGS) $(EXTRA_CFLAGS) -c $< -o $@ 100 | 101 | user_client: $(USRC_OBJS) 102 | $(CC) $(USR_FLAGS) $(EXTRA_CFLAGS) -o $(BUILD_DIR)/$@ $^ 103 | 104 | user_learner: $(USRL_OBJS) 105 | $(CC) $(USR_FLAGS) $(EXTRA_CFLAGS) -o $(BUILD_DIR)/$@ $^ 106 | 107 | ########################################################################### 108 | clean: 109 | make -C $(KDIR) M=$(BUILD_DIR) src=$(PWD) clean 110 | -rm -rf build 111 | -------------------------------------------------------------------------------- /paxos/include/storage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _STORAGE_H_ 29 | #define _STORAGE_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | #include "paxos.h" 37 | 38 | struct storage 39 | { 40 | void* handle; 41 | struct 42 | { 43 | int (*open)(void* handle); 44 | void (*close)(void* handle); 45 | int (*tx_begin)(void* handle); 46 | int (*tx_commit)(void* handle); 47 | void (*tx_abort)(void* handle); 48 | int (*get)(void* handle, iid_t iid, paxos_accepted* out); 49 | int (*put)(void* handle, paxos_accepted* acc); 50 | int (*trim)(void* handle, iid_t iid); 51 | iid_t (*get_trim_instance)(void* handle); 52 | } api; 53 | }; 54 | 55 | void storage_init(struct storage* store, int acceptor_id); 56 | int storage_open(struct storage* store); 57 | void storage_close(struct storage* store); 58 | int storage_tx_begin(struct storage* store); 59 | int storage_tx_commit(struct storage* store); 60 | void storage_tx_abort(struct storage* store); 61 | int storage_get_record(struct storage* store, iid_t iid, paxos_accepted* out); 62 | int storage_put_record(struct storage* store, paxos_accepted* acc); 63 | int storage_trim(struct storage* store, iid_t iid); 64 | iid_t storage_get_trim_instance(struct storage* store); 65 | 66 | void storage_init_mem(struct storage* s, int acceptor_id); 67 | void storage_init_lmdb(struct storage* s, int acceptor_id); 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /evpaxos/include/message.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _TCP_SENDBUF_H_ 29 | #define _TCP_SENDBUF_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | #include "common.h" 37 | #include "eth.h" 38 | #include "paxos_types.h" 39 | #include 40 | 41 | void send_paxos_message(struct net_device* dev, eth_address* addr, 42 | paxos_message* msg); 43 | void send_paxos_prepare(struct net_device* dev, eth_address* addr, 44 | paxos_prepare* pp); 45 | void send_paxos_promise(struct net_device* dev, eth_address* addr, 46 | paxos_promise* p); 47 | void send_paxos_accept(struct net_device* dev, eth_address* addr, 48 | paxos_accept* pa); 49 | void send_paxos_accepted(struct net_device* dev, eth_address* addr, 50 | paxos_accepted* p); 51 | void send_paxos_preempted(struct net_device* dev, eth_address* addr, 52 | paxos_preempted* p); 53 | void send_paxos_repeat(struct net_device* dev, eth_address* addr, 54 | paxos_repeat* p); 55 | void send_paxos_trim(struct net_device* dev, eth_address* addr, 56 | paxos_trim* t); 57 | int recv_paxos_message(paxos_message* msg, char* msg_data, 58 | paxos_message_type out, char* data, size_t size); 59 | void send_paxos_learner_hi(struct net_device* dev, eth_address* addr); 60 | void send_paxos_learner_del(struct net_device* dev, eth_address* addr); 61 | void send_paxos_acceptor_ok(struct net_device* dev, eth_address* addr); 62 | #ifdef __cplusplus 63 | } 64 | #endif 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /paxos/include/proposer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _PROPOSER_H_ 29 | #define _PROPOSER_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | #include "paxos.h" 37 | 38 | struct proposer; 39 | struct timeout_iterator; 40 | 41 | struct proposer* proposer_new(int id, int acceptors); 42 | void proposer_free(struct proposer* p); 43 | void proposer_propose(struct proposer* p, const char* value, size_t size); 44 | int proposer_prepared_count(struct proposer* p); 45 | void proposer_set_instance_id(struct proposer* p, iid_t iid); 46 | 47 | // phase 1 48 | void proposer_prepare(struct proposer* p, paxos_prepare* out); 49 | int proposer_receive_promise(struct proposer* p, paxos_promise* ack, 50 | paxos_prepare* out); 51 | 52 | // phase 2 53 | int proposer_accept(struct proposer* p, paxos_accept* out); 54 | int proposer_receive_accepted(struct proposer* p, paxos_accepted* ack); 55 | int proposer_receive_preempted(struct proposer* p, paxos_preempted* ack, 56 | paxos_prepare* out); 57 | 58 | // periodic acceptor state 59 | void proposer_receive_acceptor_state(struct proposer* p, 60 | paxos_acceptor_state* state); 61 | 62 | // timeouts 63 | struct timeout_iterator* proposer_timeout_iterator(struct proposer* p); 64 | int timeout_iterator_prepare(struct timeout_iterator* iter, 65 | paxos_prepare* out); 66 | int timeout_iterator_accept(struct timeout_iterator* iter, paxos_accept* out); 67 | void timeout_iterator_free(struct timeout_iterator* iter); 68 | 69 | #ifdef __cplusplus 70 | } 71 | #endif 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /evpaxos/include/peers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _PEERS_H_ 29 | #define _PEERS_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | #include "evpaxos.h" 37 | #include "paxos.h" 38 | #include "paxos_types.h" 39 | 40 | struct peer; 41 | struct peers; 42 | 43 | typedef void (*peer_cb)(paxos_message* m, void* arg, eth_address* src); 44 | typedef void (*peer_iter_cb)(struct net_device* dev, struct peer* p, 45 | void* arg); 46 | 47 | struct peers* peers_new(struct evpaxos_config* config, int id, char* if_name); 48 | void peers_free(struct peers* p); 49 | int peers_count(struct peers* p); 50 | eth_address* get_addr(struct peer* p); 51 | void peers_foreach_acceptor(struct peers* p, peer_iter_cb cb, void* arg); 52 | void peers_foreach_client(struct peers* p, peer_iter_cb cb, void* arg); 53 | struct peer* peers_get_acceptor(struct peers* p, int id); 54 | void add_acceptors_from_config(struct peers* p, struct evpaxos_config* conf); 55 | void printall(struct peers* p, char* name); 56 | int add_or_update_client(eth_address* addr, struct peers* p); 57 | int peer_get_id(struct peer* p); 58 | void peer_send_del(struct net_device* dev, struct peer* p, void* arg); 59 | struct net_device* get_dev(struct peers* p); 60 | int peers_missing_ok(struct peers* p); 61 | void peers_update_ok(struct peers* p, eth_address* addr); 62 | void peers_delete_learner(struct peers* p, eth_address* addr); 63 | void peers_subscribe(struct peers* p); 64 | void peers_add_subscription(struct peers* p, paxos_message_type type, 65 | peer_cb cb, void* arg); 66 | #ifdef __cplusplus 67 | } 68 | #endif 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /kpaxos/user_stats.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "user_levent.h" 7 | #include "user_stats.h" 8 | 9 | long 10 | timeval_diff(struct timeval* t1, struct timeval* t2) 11 | { 12 | long us; 13 | us = (t2->tv_sec - t1->tv_sec) * 1e6; 14 | 15 | if (us < 0) 16 | return 0; 17 | us += (t2->tv_usec - t1->tv_usec); 18 | return us; 19 | } 20 | 21 | void 22 | check_timeout(struct client* client) 23 | { 24 | struct timeval now; 25 | gettimeofday(&now, NULL); 26 | for (int i = 0; i < client->nclients; ++i) { 27 | long diff = timeval_diff(&client->nclients_time[i], &now); 28 | if (diff > TIMEOUT_US) { 29 | printf("Client %d sent expired %ld\n", i + client->id, diff); 30 | client_submit_value(client, i + client->id); 31 | } 32 | } 33 | } 34 | 35 | void 36 | on_stats(struct client* c) 37 | { 38 | double mbps = 39 | (double)(c->stats.delivered_count * c->send_buffer_len * 8) / (1024 * 1024); 40 | printf("Client: %d value/sec, %.2f Mbps\n", c->stats.delivered_count, mbps); 41 | memset(&c->stats, 0, sizeof(struct stats)); 42 | check_timeout(c); 43 | } 44 | 45 | void 46 | update_stats(struct stats* stats, struct timeval delivered, size_t size) 47 | { 48 | struct timeval tv; 49 | gettimeofday(&tv, NULL); 50 | long lat = timeval_diff(&delivered, &tv); 51 | stats->delivered_count++; 52 | stats_add(lat); 53 | } 54 | 55 | static long* a = 0; // absolute time 56 | static long* e = 0; // elapsed time between calls to stats_add 57 | static unsigned long count; 58 | static struct timespec then; 59 | 60 | void 61 | stats_init() 62 | { 63 | e = malloc(STATS_MAX_COUNT * sizeof(long)); 64 | memset(e, 0, STATS_MAX_COUNT * sizeof(long)); 65 | a = malloc(STATS_MAX_COUNT * sizeof(long)); 66 | memset(a, 0, STATS_MAX_COUNT * sizeof(long)); 67 | count = 0; 68 | clock_gettime(CLOCK_MONOTONIC_RAW, &then); 69 | } 70 | 71 | void 72 | stats_destroy() 73 | { 74 | count = 0; 75 | if (a) 76 | free(a); 77 | if (e) 78 | free(e); 79 | } 80 | 81 | void 82 | stats_add(long latency) 83 | { 84 | struct timespec now; 85 | 86 | if (count == STATS_MAX_COUNT) { 87 | printf("Stats error: array is full\n"); 88 | return; 89 | } 90 | 91 | clock_gettime(CLOCK_MONOTONIC_RAW, &now); 92 | a[count] = (now.tv_sec - then.tv_sec) * 1000000 + 93 | (now.tv_nsec - then.tv_nsec) / 1000000; 94 | e[count++] = latency; 95 | then = now; 96 | } 97 | 98 | long 99 | stats_get_avg() 100 | { 101 | int i; 102 | long avg = 0; 103 | 104 | for (i = 0; i < count; ++i) 105 | avg += (e[i] - avg) / (i + 1); 106 | 107 | return avg; 108 | } 109 | 110 | long 111 | stats_get_count() 112 | { 113 | return count; 114 | } 115 | 116 | void 117 | stats_print() 118 | { 119 | printf("Statistics with %lu entries average of %ldus\n", count, 120 | stats_get_avg()); 121 | } 122 | 123 | void 124 | stats_persist(const char* file) 125 | { 126 | int i; 127 | long abs = 0; 128 | 129 | FILE* f = fopen(file, "w+"); 130 | char line[128]; 131 | 132 | if (f) { 133 | sprintf(line, "#ORDER\tLATENCY\tABS\n"); 134 | fwrite(line, 1, strlen(line), f); 135 | for (i = 0; i < count; i++) { 136 | abs += a[i]; 137 | sprintf(line, "%d\t%ld\t%ld\n", (i + 1), e[i], abs); 138 | fwrite(line, 1, strlen(line), f); 139 | } 140 | sync(); 141 | fclose(f); 142 | } else { 143 | printf("Stats: could not save statistics to file '%s'\n", file); 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /kpaxos/user_learner.c: -------------------------------------------------------------------------------- 1 | #include "user_eth.h" 2 | #include "user_levent.h" 3 | #include "user_stats.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static int stop = 1; 11 | 12 | void 13 | stop_execution(int signo) 14 | { 15 | stop = 0; 16 | } 17 | 18 | static void 19 | unpack_message(struct server* serv, size_t len) 20 | { 21 | struct user_msg* mess = (struct user_msg*)serv->ethop.rec_buffer; 22 | struct client_value* val = (struct client_value*)mess->value; 23 | struct connection* conn = find_connection(serv, val->client_id); 24 | if (conn) 25 | eth_sendmsg(&serv->ethop, conn->address, mess, len); 26 | } 27 | 28 | static void 29 | read_file(struct server* serv) 30 | { 31 | int len = read(serv->fileop.fd, serv->ethop.rec_buffer, ETH_DATA_LEN); 32 | 33 | if (len < 0) 34 | return; 35 | 36 | if (len == 0) { 37 | printf("Stopped by kernel module\n"); 38 | stop = 0; 39 | } 40 | unpack_message(serv, len); 41 | } 42 | 43 | static void 44 | change_conn_status(struct server* serv, char* mess, uint8_t dest_addr[ETH_ALEN]) 45 | { 46 | int* buff = (int*)mess; 47 | if (buff[0] == OPEN_CONN) { 48 | int id = add_connection(serv, buff[1], buff[2], dest_addr); 49 | int buffs[2]; 50 | buffs[0] = OK; 51 | buffs[1] = id; 52 | eth_sendmsg(&serv->ethop, dest_addr, buffs, sizeof(buffs)); 53 | } 54 | if (buff[0] == CLOSE_CONN) { 55 | rem_connection(serv, buff[1]); 56 | } 57 | } 58 | 59 | void 60 | read_socket(struct server* serv) 61 | { 62 | ssize_t len; 63 | uint8_t src_addr[ETH_ALEN]; 64 | len = 65 | eth_recmsg(&serv->ethop, src_addr, serv->ethop.rec_buffer, ETH_DATA_LEN); 66 | if (len > 0) 67 | change_conn_status(serv, serv->ethop.rec_buffer, src_addr); 68 | } 69 | 70 | static void 71 | make_learner(struct server* serv) 72 | { 73 | struct pollfd pol[2]; // 2 events: socket and file 74 | 75 | // chardevice 76 | if (open_file(&serv->fileop)) 77 | goto cleanup; 78 | 79 | // socket 80 | if (eth_init(&serv->ethop)) 81 | goto cleanup; 82 | 83 | if (eth_listen(&serv->ethop)) 84 | goto cleanup; 85 | 86 | pol[0].fd = serv->ethop.socket; 87 | pol[0].events = POLLIN; 88 | pol[1].fd = serv->fileop.fd; 89 | pol[1].events = POLLIN; 90 | 91 | while (stop) { 92 | poll(pol, 2, -1); 93 | // send delivered values via socket 94 | if (pol[0].revents & POLLIN) { 95 | read_socket(serv); 96 | } else if (pol[1].revents & POLLIN) { // communicate to chardevice via file 97 | read_file(serv); 98 | } 99 | } 100 | 101 | cleanup: 102 | server_free(serv); 103 | } 104 | 105 | static void 106 | check_args(int argc, char* argv[], struct server* serv) 107 | { 108 | int opt = 0, idx = 0; 109 | 110 | static struct option options[] = { { "chardev_id", required_argument, 0, 111 | 'c' }, 112 | { "if_name", required_argument, 0, 'i' }, 113 | { "help", no_argument, 0, 'h' }, 114 | { 0, 0, 0, 0 } }; 115 | 116 | while ((opt = getopt_long(argc, argv, "c:i:h", options, &idx)) != -1) { 117 | switch (opt) { 118 | case 'c': 119 | serv->fileop.char_device_id = atoi(optarg); 120 | break; 121 | case 'i': 122 | serv->ethop.if_name = optarg; 123 | break; 124 | default: 125 | usage(argv[0], 0); 126 | } 127 | } 128 | } 129 | 130 | int 131 | main(int argc, char* argv[]) 132 | { 133 | struct server* serv = server_new(); 134 | serv->ethop.if_name = "enp0s3"; 135 | serv->fileop.char_device_id = 0; 136 | new_connection_list(serv); 137 | 138 | check_args(argc, argv, serv); 139 | 140 | printf("if_name %s\n", serv->ethop.if_name); 141 | printf("chardevice /dev/paxos/klearner%c\n", 142 | serv->fileop.char_device_id + '0'); 143 | signal(SIGINT, stop_execution); 144 | make_learner(serv); 145 | 146 | return 0; 147 | } 148 | -------------------------------------------------------------------------------- /paxos/carray.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "carray.h" 29 | #include "paxos.h" 30 | #include 31 | 32 | struct carray 33 | { 34 | int head; 35 | int tail; 36 | int size; 37 | int count; 38 | void** array; 39 | }; 40 | 41 | static int carray_full(struct carray* a); 42 | static void carray_grow(struct carray* a); 43 | static void* carray_at(struct carray* a, int i); 44 | 45 | struct carray* 46 | carray_new(int size) 47 | { 48 | struct carray* a; 49 | a = pmalloc(sizeof(struct carray)); 50 | if (a == NULL) 51 | paxos_log_error("A IS NULL"); 52 | a->head = 0; 53 | a->tail = 0; 54 | a->size = size; 55 | a->count = 0; 56 | a->array = vmalloc(sizeof(void*) * a->size); 57 | if (a == NULL) 58 | paxos_log_error("ARRAY IS NULL"); 59 | return a; 60 | } 61 | 62 | void 63 | carray_free(struct carray* a) 64 | { 65 | vfree(a->array); 66 | pfree(a); 67 | } 68 | 69 | int 70 | carray_empty(struct carray* a) 71 | { 72 | return a->count == 0; 73 | } 74 | 75 | int 76 | carray_size(struct carray* a) 77 | { 78 | return a->size; 79 | } 80 | 81 | int 82 | carray_push_back(struct carray* a, void* p) 83 | { 84 | if (carray_full(a)) 85 | carray_grow(a); 86 | a->array[a->tail] = p; 87 | a->tail = (a->tail + 1) % a->size; 88 | a->count++; 89 | return 0; 90 | } 91 | 92 | void* 93 | carray_pop_front(struct carray* a) 94 | { 95 | void* p; 96 | if (carray_empty(a)) 97 | return NULL; 98 | p = a->array[a->head]; 99 | a->head = (a->head + 1) % a->size; 100 | a->count--; 101 | return p; 102 | } 103 | 104 | void 105 | carray_foreach(struct carray* a, void (*carray_cb)(void*)) 106 | { 107 | int i; 108 | for (i = 0; i < a->count; ++i) 109 | carray_cb(carray_at(a, i)); 110 | } 111 | 112 | static int 113 | carray_full(struct carray* a) 114 | { 115 | return a->count == a->size; 116 | } 117 | 118 | static void 119 | carray_grow(struct carray* a) 120 | { 121 | if (printk_ratelimit()) 122 | paxos_log_error("Cannot allocate during execution! Carray value lost!"); 123 | // int i; 124 | // void** tmp = vmalloc(sizeof(void*) * a->size * 2); 125 | // for (i = 0; i < a->count; i++) { 126 | // tmp[i] = carray_at(a, i); 127 | // } 128 | // a->head = 0; 129 | // a->tail = a->count; 130 | // a->size *= 2; 131 | // vfree(a->array); 132 | // a->array = tmp; 133 | } 134 | 135 | static void* 136 | carray_at(struct carray* a, int i) 137 | { 138 | return a->array[(a->head + i) % a->size]; 139 | } 140 | -------------------------------------------------------------------------------- /paxos/include/paxos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _LIBPAXOS_H_ 29 | #define _LIBPAXOS_H_ 30 | 31 | #ifdef __cplusplus 32 | extern "C" 33 | { 34 | #endif 35 | 36 | #include "common.h" 37 | #include "paxos_types.h" 38 | #include 39 | #include 40 | 41 | /* Paxos instance ids and ballots */ 42 | typedef uint32_t iid_t; 43 | typedef uint32_t ballot_t; 44 | 45 | /* Logging and verbosity levels */ 46 | typedef enum 47 | { 48 | PAXOS_LOG_QUIET = 0, 49 | PAXOS_LOG_ERROR = 1, 50 | PAXOS_LOG_INFO = 2, 51 | PAXOS_LOG_DEBUG = 3 52 | } paxos_log_level; 53 | 54 | /* Supported storage backends */ 55 | typedef enum 56 | { 57 | PAXOS_MEM_STORAGE = 0, 58 | PAXOS_LMDB_STORAGE = 1 59 | } paxos_storage_backend; 60 | 61 | /* Configuration */ 62 | struct paxos_config 63 | { 64 | /* General configuration */ 65 | paxos_log_level verbosity; 66 | int tcp_nodelay; 67 | 68 | /* Learner */ 69 | int learner_catch_up; 70 | 71 | /* Proposer */ 72 | int proposer_timeout; 73 | int proposer_preexec_window; 74 | 75 | /* Acceptor */ 76 | paxos_storage_backend storage_backend; 77 | int trash_files; 78 | 79 | /* lmdb storage configuration */ 80 | int lmdb_sync; 81 | char* lmdb_env_path; 82 | size_t lmdb_mapsize; 83 | }; 84 | 85 | extern struct paxos_config paxos_config; 86 | 87 | /* Core functions */ 88 | int paxos_quorum(int acceptors); 89 | paxos_value* paxos_value_new(const char* v, size_t s); 90 | void paxos_value_free(paxos_value* v); 91 | void paxos_promise_destroy(paxos_promise* p); 92 | void paxos_accept_destroy(paxos_accept* a); 93 | void paxos_accepted_destroy(paxos_accepted* a); 94 | void paxos_message_destroy(paxos_message* m); 95 | void paxos_accepted_free(paxos_accepted* a); 96 | void paxos_log(int level, const char* format, va_list ap); 97 | void paxos_log_error(const char* format, ...); 98 | void paxos_log_info(const char* format, ...); 99 | void paxos_log_debug(const char* format, ...); 100 | 101 | /* 102 | MAX_N_OF_PROPOSERS should be removed. 103 | The maximum number of proposers must be fixed beforehand 104 | (this is because of unique ballot generation). 105 | The proposers must be started with different IDs. 106 | This number MUST be a power of 10. 107 | */ 108 | #define MAX_N_OF_PROPOSERS 10 109 | 110 | #ifdef __cplusplus 111 | } 112 | #endif 113 | 114 | #endif 115 | -------------------------------------------------------------------------------- /paxos/storage_mem.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "common.h" 29 | #include "storage.h" 30 | #include 31 | #include 32 | 33 | static const int MAX_SIZE = 1000000; 34 | 35 | typedef struct store 36 | { 37 | paxos_accepted msg; 38 | char data[ETH_DATA_LEN - sizeof(paxos_accepted)]; 39 | } store_t; 40 | 41 | struct mem_storage 42 | { 43 | store_t* st; 44 | iid_t trim_iid; // just for compatibility 45 | }; 46 | 47 | static struct mem_storage* 48 | mem_storage_new(int acceptor_id) 49 | { 50 | struct mem_storage* s = vmalloc(sizeof(struct mem_storage)); 51 | 52 | s->st = vmalloc(MAX_SIZE * sizeof(struct store)); 53 | memset(s->st, 0, MAX_SIZE * sizeof(struct store)); 54 | s->trim_iid = 0; 55 | return s; 56 | } 57 | 58 | static int 59 | mem_storage_open(void* handle) 60 | { 61 | return 0; 62 | } 63 | 64 | static void 65 | mem_storage_close(void* handle) 66 | { 67 | struct mem_storage* s = handle; 68 | if (s) { 69 | vfree(s->st); 70 | vfree(s); 71 | } 72 | } 73 | 74 | static int 75 | mem_storage_tx_begin(void* handle) 76 | { 77 | return 0; 78 | } 79 | 80 | static int 81 | mem_storage_tx_commit(void* handle) 82 | { 83 | return 0; 84 | } 85 | 86 | static void 87 | mem_storage_tx_abort(void* handle) 88 | {} 89 | 90 | static int 91 | mem_storage_get(void* handle, iid_t iid, paxos_accepted* out) 92 | { 93 | struct mem_storage* s = handle; 94 | int idx = iid % MAX_SIZE; 95 | 96 | if (s->st[idx].msg.iid == iid) { 97 | memcpy(out, &s->st[idx].msg, sizeof(paxos_accepted)); 98 | if (out->value.paxos_value_len > 0) { 99 | out->value.paxos_value_val = pmalloc(out->value.paxos_value_len); 100 | memcpy(out->value.paxos_value_val, s->st[idx].data, 101 | out->value.paxos_value_len); 102 | } 103 | return 1; 104 | } 105 | 106 | return 0; 107 | } 108 | 109 | static int 110 | mem_storage_put(void* handle, paxos_accepted* acc) 111 | { 112 | struct mem_storage* s = handle; 113 | int idx = acc->iid % MAX_SIZE; 114 | 115 | memcpy(&s->st[idx].msg, acc, sizeof(paxos_accepted)); 116 | if (s->st[idx].msg.value.paxos_value_len > sizeof(s->st[idx].data)) { 117 | LOG_ERROR("Data will be truncated."); 118 | s->st[idx].msg.value.paxos_value_len = sizeof(s->st[idx].data); 119 | } 120 | memcpy(s->st[idx].data, acc->value.paxos_value_val, 121 | s->st[idx].msg.value.paxos_value_len); 122 | return 0; 123 | } 124 | 125 | static int 126 | mem_storage_trim(void* handle, iid_t iid) 127 | { 128 | struct mem_storage* s = handle; 129 | s->trim_iid = iid; 130 | return 0; 131 | } 132 | 133 | static iid_t 134 | mem_storage_get_trim_instance(void* handle) 135 | { 136 | struct mem_storage* s = handle; 137 | return s->trim_iid; 138 | } 139 | 140 | void 141 | storage_init_mem(struct storage* s, int acceptor_id) 142 | { 143 | s->handle = mem_storage_new(acceptor_id); 144 | s->api.open = mem_storage_open; 145 | s->api.close = mem_storage_close; 146 | s->api.tx_begin = mem_storage_tx_begin; 147 | s->api.tx_commit = mem_storage_tx_commit; 148 | s->api.tx_abort = mem_storage_tx_abort; 149 | s->api.get = mem_storage_get; 150 | s->api.put = mem_storage_put; 151 | s->api.trim = mem_storage_trim; 152 | s->api.get_trim_instance = mem_storage_get_trim_instance; 153 | } -------------------------------------------------------------------------------- /evpaxos/evreplica.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "evpaxos_internal.h" 29 | #include "message.h" 30 | #include 31 | 32 | struct evpaxos_replica 33 | { 34 | struct peers* peers; 35 | struct evlearner* learner; 36 | struct evproposer* proposer; 37 | struct evacceptor* acceptor; 38 | deliver_function deliver; 39 | void* arg; 40 | }; 41 | 42 | static void 43 | evpaxos_replica_deliver(unsigned iid, char* value, size_t size, void* arg) 44 | { 45 | struct evpaxos_replica* r = arg; 46 | evproposer_set_instance_id(r->proposer, iid); 47 | if (r->deliver) { 48 | r->deliver(iid, value, size, r->arg); 49 | } 50 | } 51 | 52 | struct evpaxos_replica* 53 | evpaxos_replica_init(int id, deliver_function f, void* arg, char* if_name, 54 | char* path) 55 | { 56 | struct evpaxos_replica* replica; 57 | struct evpaxos_config* config; 58 | 59 | config = evpaxos_config_read(path); 60 | if (config == NULL) { 61 | return NULL; 62 | } 63 | 64 | replica = pmalloc(sizeof(struct evpaxos_replica)); 65 | if (replica == NULL) { 66 | return NULL; 67 | } 68 | 69 | replica->peers = peers_new(config, id, if_name); 70 | if (replica->peers == NULL) 71 | return NULL; 72 | add_acceptors_from_config(replica->peers, config); 73 | printall(replica->peers, "Replica"); 74 | replica->deliver = f; 75 | replica->arg = arg; 76 | replica->acceptor = evacceptor_init_internal(id, config, replica->peers); 77 | replica->learner = evlearner_init_internal(config, replica->peers, 78 | evpaxos_replica_deliver, replica); 79 | replica->proposer = evproposer_init_internal(id, config, replica->peers); 80 | peers_subscribe(replica->peers); 81 | evlearner_send_hi(replica->peers); 82 | evproposer_preexec_once(replica->proposer); 83 | evpaxos_config_free(config); 84 | return replica; 85 | } 86 | 87 | void 88 | evpaxos_replica_free(struct evpaxos_replica* r) 89 | { 90 | printall(r->peers, "REPLICA"); 91 | if (r->learner) 92 | evlearner_free_internal(r->learner); 93 | if (r->proposer) 94 | evproposer_free_internal(r->proposer); 95 | if (r->acceptor) 96 | evacceptor_free_internal(r->acceptor); 97 | 98 | peers_free(r->peers); 99 | pfree(r); 100 | } 101 | 102 | void 103 | evpaxos_replica_set_instance_id(struct evpaxos_replica* r, unsigned iid) 104 | { 105 | if (r->learner) 106 | evlearner_set_instance_id(r->learner, iid); 107 | evproposer_set_instance_id(r->proposer, iid); 108 | } 109 | 110 | static void 111 | peer_send_trim(struct net_device* dev, struct peer* p, void* arg) 112 | { 113 | send_paxos_trim(dev, get_addr(p), arg); 114 | } 115 | 116 | void 117 | evpaxos_replica_send_trim(struct evpaxos_replica* r, unsigned iid) 118 | { 119 | paxos_trim trim = { iid }; 120 | peers_foreach_acceptor(r->peers, peer_send_trim, &trim); 121 | } 122 | 123 | // void evpaxos_replica_submit(struct evpaxos_replica *r, char *value, int size) 124 | // { 125 | // int i; 126 | // struct peer *p; 127 | // for (i = 0; i < peers_count(r->peers); ++i) { 128 | // p = peers_get_acceptor(r->peers, i); 129 | // paxos_submit(get_dev(r->peers), p->, value, size); 130 | // return; 131 | // } 132 | // } 133 | 134 | int 135 | evpaxos_replica_count(struct evpaxos_replica* r) 136 | { 137 | return peers_count(r->peers); 138 | } 139 | -------------------------------------------------------------------------------- /paxos/include/paxos_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _PAXOS_TYPES_H_ 29 | #define _PAXOS_TYPES_H_ 30 | 31 | #include 32 | 33 | typedef unsigned char msgpack_packer; 34 | 35 | struct paxos_value 36 | { 37 | int paxos_value_len; 38 | char* paxos_value_val; 39 | }; 40 | typedef struct paxos_value paxos_value; 41 | 42 | struct paxos_prepare 43 | { 44 | uint32_t iid; 45 | uint32_t ballot; 46 | }; 47 | typedef struct paxos_prepare paxos_prepare; 48 | 49 | struct paxos_promise 50 | { 51 | uint32_t aid; 52 | uint32_t iid; 53 | uint32_t ballot; 54 | uint32_t value_ballot; 55 | paxos_value value; 56 | }; 57 | typedef struct paxos_promise paxos_promise; 58 | 59 | struct paxos_accept 60 | { 61 | uint32_t iid; 62 | uint32_t promise_iid; 63 | uint32_t ballot; 64 | paxos_value value; 65 | }; 66 | typedef struct paxos_accept paxos_accept; 67 | 68 | struct paxos_accepted 69 | { 70 | uint32_t aid; 71 | uint32_t iid; 72 | uint32_t promise_iid; 73 | uint32_t ballot; 74 | uint32_t value_ballot; 75 | paxos_value value; 76 | }; 77 | typedef struct paxos_accepted paxos_accepted; 78 | 79 | struct paxos_preempted 80 | { 81 | uint32_t aid; 82 | uint32_t iid; 83 | uint32_t ballot; 84 | }; 85 | typedef struct paxos_preempted paxos_preempted; 86 | 87 | struct paxos_repeat 88 | { 89 | uint32_t from; 90 | uint32_t to; 91 | }; 92 | typedef struct paxos_repeat paxos_repeat; 93 | 94 | struct paxos_trim 95 | { 96 | uint32_t iid; 97 | }; 98 | typedef struct paxos_trim paxos_trim; 99 | 100 | struct paxos_acceptor_state 101 | { 102 | uint32_t aid; 103 | uint32_t trim_iid; 104 | }; 105 | typedef struct paxos_acceptor_state paxos_acceptor_state; 106 | 107 | struct paxos_client_value 108 | { 109 | paxos_value value; 110 | }; 111 | typedef struct paxos_client_value paxos_client_value; 112 | 113 | struct paxos_learner_hi 114 | {}; 115 | typedef struct paxos_learner_hi paxos_learner_hi; 116 | 117 | struct paxos_learner_del 118 | {}; 119 | typedef struct paxos_learner_del paxos_learner_del; 120 | 121 | struct paxos_acceptor_ok 122 | {}; 123 | typedef struct paxos_acceptor_ok paxos_acceptor_ok; 124 | 125 | enum paxos_message_type 126 | { 127 | PAXOS_PREPARE = 0xcafa, // this MUST be the first element of the enum 128 | PAXOS_PROMISE, 129 | PAXOS_ACCEPT, 130 | PAXOS_ACCEPTED, 131 | PAXOS_PREEMPTED, 132 | PAXOS_REPEAT, 133 | PAXOS_TRIM, 134 | PAXOS_ACCEPTOR_STATE, 135 | PAXOS_CLIENT_VALUE, 136 | PAXOS_LEARNER_HI, 137 | PAXOS_LEARNER_DEL, 138 | PAXOS_ACCEPTOR_OK, 139 | N_ELEMENTS // this MUST be the last element of the enum 140 | }; 141 | 142 | #define N_PAXOS_TYPES N_ELEMENTS - PAXOS_PREPARE 143 | #define GET_PAXOS_INDEX(n) n - PAXOS_PREPARE 144 | #define GET_PAXOS(n) n + PAXOS_PREPARE 145 | typedef enum paxos_message_type paxos_message_type; 146 | 147 | struct paxos_message 148 | { 149 | paxos_message_type type; 150 | union 151 | { 152 | paxos_prepare prepare; 153 | paxos_promise promise; 154 | paxos_accept accept; 155 | paxos_accepted accepted; 156 | paxos_preempted preempted; 157 | paxos_repeat repeat; 158 | paxos_trim trim; 159 | paxos_acceptor_state state; 160 | paxos_client_value client_value; 161 | paxos_learner_hi learner_hi; 162 | paxos_learner_del learner_del; 163 | paxos_acceptor_ok accept_ok; 164 | } u; 165 | }; 166 | typedef struct paxos_message paxos_message; 167 | 168 | #endif 169 | -------------------------------------------------------------------------------- /evpaxos/eth.c: -------------------------------------------------------------------------------- 1 | #include "eth.h" 2 | #include "message.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAX_CALLBACK 3 13 | 14 | struct callback 15 | { 16 | struct packet_type pt; 17 | int cb_index; 18 | peer_cb cb[MAX_CALLBACK]; 19 | void* arg[MAX_CALLBACK]; 20 | }; 21 | 22 | static struct callback cbs[N_PAXOS_TYPES]; 23 | static int if_lo = 0; 24 | 25 | static int packet_recv(struct sk_buff* sk, struct net_device* dev, 26 | struct packet_type* pt, struct net_device* dev2); 27 | 28 | struct net_device* 29 | eth_init(const char* if_name) 30 | { 31 | memset(cbs, 0, sizeof(cbs)); 32 | if (memcmp(if_name, "lo", 3) == 0) 33 | if_lo = 1; 34 | return dev_get_by_name(&init_net, if_name); 35 | } 36 | 37 | int 38 | eth_subscribe(struct net_device* dev, uint16_t proto, peer_cb cb, void* arg) 39 | { 40 | int i = GET_PAXOS_INDEX(proto); // cbs[i] 41 | 42 | if (i < 0 || i >= N_PAXOS_TYPES) { 43 | paxos_log_error("Wrong protocol!"); 44 | return 0; 45 | } 46 | 47 | if (cbs[i].cb_index >= MAX_CALLBACK) { 48 | paxos_log_error("Callback full!"); 49 | return 0; 50 | } 51 | 52 | for (int k = 0; k < cbs[i].cb_index; k++) { 53 | if (cbs[i].cb[k] == cb) { 54 | paxos_log_error("Callback already present!"); 55 | return 0; 56 | } 57 | } 58 | 59 | cbs[i].cb[cbs[i].cb_index] = cb; 60 | cbs[i].arg[cbs[i].cb_index++] = arg; 61 | return 1; 62 | } 63 | 64 | int 65 | eth_listen(struct net_device* dev) 66 | { 67 | for (int i = 0; i < N_PAXOS_TYPES; i++) { 68 | if (cbs[i].cb_index > 0) { 69 | cbs[i].pt.type = htons(GET_PAXOS(i)); 70 | cbs[i].pt.func = packet_recv; 71 | cbs[i].pt.dev = dev; 72 | paxos_log_debug("Added callback for proto %d", i); 73 | dev_add_pack(&cbs[i].pt); 74 | } 75 | } 76 | return 1; 77 | } 78 | 79 | static int 80 | packet_recv(struct sk_buff* skb, struct net_device* dev, struct packet_type* pt, 81 | struct net_device* src_dev) 82 | { 83 | uint16_t proto = ntohs(skb->protocol); 84 | int i = GET_PAXOS_INDEX(proto); 85 | paxos_message msg; 86 | char msg_data[ETH_DATA_LEN]; 87 | struct ethhdr* eth = eth_hdr(skb); 88 | size_t len = skb->len; 89 | char data[ETH_DATA_LEN]; 90 | char* data_p = data; 91 | 92 | skb_copy_bits(skb, 0, data, len); 93 | 94 | if (!if_lo && memcmp(eth->h_source, dev->dev_addr, ETH_ALEN) == 0) { 95 | data_p += ETH_HLEN; 96 | len -= ETH_HLEN; 97 | } 98 | 99 | recv_paxos_message(&msg, msg_data, proto, data_p, len); 100 | for (int k = 0; k < cbs[i].cb_index; k++) { 101 | cbs[i].cb[k](&msg, cbs[i].arg[k], eth->h_source); 102 | } 103 | 104 | kfree_skb(skb); 105 | return 0; 106 | } 107 | 108 | // reimplemented dev_loopback_xmit without the warning 109 | void 110 | dev_loopback_xmit2(struct sk_buff* skb) 111 | { 112 | skb_reset_mac_header(skb); 113 | __skb_pull(skb, skb_network_offset(skb)); 114 | skb->pkt_type = PACKET_LOOPBACK; 115 | skb->ip_summed = CHECKSUM_UNNECESSARY; 116 | skb_dst_force(skb); 117 | netif_rx_ni(skb); 118 | } 119 | 120 | int 121 | eth_send(struct net_device* dev, uint8_t dest_addr[ETH_ALEN], uint16_t proto, 122 | const char* msg, size_t len) 123 | { 124 | int ret = 0; 125 | unsigned char* data; 126 | 127 | struct sk_buff* skb = alloc_skb(ETH_FRAME_LEN, GFP_ATOMIC); 128 | 129 | skb->dev = dev; 130 | skb->pkt_type = PACKET_OUTGOING; 131 | 132 | skb_reserve(skb, ETH_HLEN); 133 | /*changing Mac address */ 134 | struct ethhdr* eth = (struct ethhdr*)skb_push(skb, ETH_HLEN); 135 | skb->protocol = eth->h_proto = htons(proto); 136 | memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); 137 | memcpy(eth->h_dest, dest_addr, ETH_ALEN); 138 | 139 | /* put the data and send the packet */ 140 | if (len > ETH_DATA_LEN) 141 | len = ETH_DATA_LEN; 142 | 143 | data = skb_put(skb, len); 144 | memcpy(data, msg, len); 145 | if (memcmp(dest_addr, dev->dev_addr, ETH_ALEN) == 0) { 146 | dev_loopback_xmit2(skb); 147 | } else { 148 | ret = dev_queue_xmit(skb); 149 | } 150 | return !ret; 151 | } 152 | 153 | int 154 | eth_destroy(struct net_device* dev) 155 | { 156 | int i; 157 | 158 | for (i = 0; i < N_PAXOS_TYPES; ++i) { 159 | if (cbs[i].cb_index > 0) 160 | dev_remove_pack(&cbs[i].pt); 161 | } 162 | 163 | return 1; 164 | } 165 | 166 | int 167 | str_to_mac(const char* str, uint8_t daddr[ETH_ALEN]) 168 | { 169 | int values[6], i; 170 | if (6 == sscanf(str, "%x:%x:%x:%x:%x:%x", &values[0], &values[1], &values[2], 171 | &values[3], &values[4], &values[5])) { 172 | /* convert to uint8_t */ 173 | for (i = 0; i < 6; ++i) 174 | daddr[i] = (uint8_t)values[i]; 175 | return 1; 176 | } 177 | return 0; 178 | } 179 | 180 | int 181 | mac_to_str(uint8_t daddr[ETH_ALEN], char* str) 182 | { 183 | sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x\n", daddr[0], daddr[1], daddr[2], 184 | daddr[3], daddr[4], daddr[5]); 185 | return 1; 186 | } 187 | -------------------------------------------------------------------------------- /paxos/paxos.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2015, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "paxos.h" 29 | #include 30 | #include 31 | 32 | struct paxos_config paxos_config = { .verbosity = PAXOS_LOG_ERROR, 33 | .tcp_nodelay = 1, 34 | .learner_catch_up = 0, 35 | .proposer_timeout = 1, 36 | .proposer_preexec_window = 128, 37 | .storage_backend = PAXOS_MEM_STORAGE, 38 | .trash_files = 0, 39 | .lmdb_sync = 0, 40 | .lmdb_env_path = "/tmp/acceptor", 41 | .lmdb_mapsize = 10 * 1024 * 1024 }; 42 | 43 | int 44 | paxos_quorum(int acceptors) 45 | { 46 | return (acceptors / 2) + 1; 47 | } 48 | 49 | paxos_value* 50 | paxos_value_new(const char* value, size_t size) 51 | { 52 | paxos_value* v; 53 | v = pmalloc(sizeof(paxos_value)); 54 | v->paxos_value_len = size; 55 | v->paxos_value_val = pmalloc(size); 56 | memcpy(v->paxos_value_val, value, size); 57 | return v; 58 | } 59 | 60 | void 61 | paxos_value_free(paxos_value* v) 62 | { 63 | pfree(v->paxos_value_val); 64 | pfree(v); 65 | } 66 | 67 | static void 68 | paxos_value_destroy(paxos_value* v) 69 | { 70 | if (v->paxos_value_len > 0) 71 | pfree(v->paxos_value_val); 72 | } 73 | 74 | void 75 | paxos_accepted_free(paxos_accepted* a) 76 | { 77 | paxos_accepted_destroy(a); 78 | pfree(a); 79 | } 80 | 81 | void 82 | paxos_promise_destroy(paxos_promise* p) 83 | { 84 | paxos_value_destroy(&p->value); 85 | } 86 | 87 | void 88 | paxos_accept_destroy(paxos_accept* p) 89 | { 90 | paxos_value_destroy(&p->value); 91 | } 92 | 93 | void 94 | paxos_accepted_destroy(paxos_accepted* p) 95 | { 96 | paxos_value_destroy(&p->value); 97 | } 98 | 99 | void 100 | paxos_client_value_destroy(paxos_client_value* p) 101 | { 102 | paxos_value_destroy(&p->value); 103 | } 104 | 105 | void 106 | paxos_message_destroy(paxos_message* m) 107 | { 108 | switch (m->type) { 109 | case PAXOS_PROMISE: 110 | paxos_promise_destroy(&m->u.promise); 111 | break; 112 | case PAXOS_ACCEPT: 113 | paxos_accept_destroy(&m->u.accept); 114 | break; 115 | case PAXOS_ACCEPTED: 116 | paxos_accepted_destroy(&m->u.accepted); 117 | break; 118 | case PAXOS_CLIENT_VALUE: 119 | paxos_client_value_destroy(&m->u.client_value); 120 | break; 121 | default: 122 | break; 123 | } 124 | } 125 | 126 | void 127 | paxos_log(int level, const char* format, va_list ap) 128 | { 129 | if (level > paxos_config.verbosity) { 130 | return; 131 | } 132 | char msg[1000]; 133 | vsnprintf(msg, sizeof(msg), format, ap); 134 | 135 | switch (level) { 136 | case PAXOS_LOG_INFO: 137 | LOG_INFO("%s", msg); 138 | // printk("%s\n", msg); 139 | break; 140 | case PAXOS_LOG_DEBUG: 141 | LOG_DEBUG("%s", msg); 142 | // printk(KERN_INFO "%s\n", msg); 143 | break; 144 | case PAXOS_LOG_ERROR: 145 | LOG_ERROR("%s", msg); 146 | // printk(KERN_ERR "%s\n", msg); 147 | break; 148 | } 149 | } 150 | 151 | void 152 | paxos_log_error(const char* format, ...) 153 | { 154 | va_list ap; 155 | va_start(ap, format); 156 | paxos_log(PAXOS_LOG_ERROR, format, ap); 157 | va_end(ap); 158 | } 159 | 160 | void 161 | paxos_log_info(const char* format, ...) 162 | { 163 | va_list ap; 164 | va_start(ap, format); 165 | paxos_log(PAXOS_LOG_INFO, format, ap); 166 | va_end(ap); 167 | } 168 | 169 | void 170 | paxos_log_debug(const char* format, ...) 171 | { 172 | va_list ap; 173 | va_start(ap, format); 174 | paxos_log(PAXOS_LOG_DEBUG, format, ap); 175 | va_end(ap); 176 | } 177 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kernel_Paxos 2 | Kernel Modules that implements Paxos protocol 3 | 4 | Tested on Ubuntu 17.04 zesty, kernel 4.10.0-33-generic and CentOS Linux kernel 3.10.0. 5 | 6 | The logic implementation of Paxos protocol used in these modules has been taken from [Libpaxos](http://libpaxos.sourceforge.net/) 7 | 8 | ## Description 9 | ### Kernel space 10 | There are 5 kind of modules: KAcceptor, KProposer, KLearner, KClient and KReplica. 11 | 12 | KAcceptor: Simulates the role of an Acceptor.
13 | An acceptor receives 1A (prepare) and 2A (accept request) from a Proposer, and sends it back 1B (promise) and 2B (accepted). It also sends 2B messages to all the Learners. 14 | 15 | KProposer: Simulates the role of a Proposer.
16 | A proposer sends 1A (prepare) and 2A (accept request) to the Acceptors, receiving back 1B (promise) and 2B (accepted). It also receives CVs (Client Values) from Client. 17 | 18 | KLearner: Simulates the role of a Learner.
19 | A Learner receives 2B (accepted) messages from Acceptor and delivers them to the user space application(s). 20 | 21 | KClient: Simulates the role of a Client and Learner.
22 | The KClient sends a message to a KProposer, waiting that its internal Learner receives the value back. It keeps track of the delay between sending and receiving to calculate statistics (troughput, latency). The KClient can be substituted by the Client application in user space 23 | 24 | KReplica: Simulates the role of an Replica.
25 | A Replica contains the logic of Proposer, Acceptor and Learner. 26 | 27 | ### User space 28 | 29 | There are 2 kind of user space applications: Client and Learner. 30 | 31 | Client: Sends message to the KProposer that is in kernel space. A Client can either connect to a KLearner via chardavice or to an user space Learner application via Ethernet messages. 32 | 33 | Learner: Connects to a KLearner via chardevice. It sends received value to the Client through user space ethernet messages. 34 | 35 | These are some of the possible connections that can be created.
36 | Other examples include using Replica instead of Proposer + 3 Acceptors and kernel instead of user space Clients.

37 | ![Paxos_images.png](./.images/Paxos_images.png) 38 | 39 | ## Difference from Libpaxos 40 | 41 | There are some differences between Kernel_Paxos and Libpaxos, since it uses libevent, msgpacker and khash. 42 | These are user space libraries, that cannot be used in kernel modules. 43 | 44 | libevent: used to handle asynchronous timeouts and TCP connections between all Libpaxos roles. Kernel_Paxos uses raw ethernet frames. 45 | 46 | msgpacker: used to serialize messages, so that they can be read by big and little endian platforms. Kernel_Paxos uses a custom-made variant of it. 47 | 48 | khash: khash uses floating point internally, which cannot be used inside the Linux kernel, for portability reasons. Therefore uthash was preferred, since it does not use floating point operations. Acceptors use a circular buffer to save instances. 49 | 50 | lmdb: Libpaxos offers the use of a database where values can be saved permanently. This is not implemented here, everything is kept in memory. 51 | 52 | In addition the aforementioned, there are little changes in the logic: 53 | - Since communication is connectionless, any KAcceptor must know the address of KLearners. Therefore, once a KLearner is started, it sends "hi" to the KAcceptor, that saves the receiving address and replies back "ok". If a KAcceptor does not reply back, the Learner keeps sending "hi" to the given addresses. 54 | 55 | - A KLearner also sends a "delete" message to the KAcceptor when it is being unloaded, so that it can delete its entry from the known addresses. 56 | 57 | - Since a Client value can be lost (connectionless communication), the Client waits at most one second for receiving it back. If no value is received in that period of time, it sends the value again to the KProposer. This feature is also implemented inside the KClient. 58 | 59 | 60 | - The maximum ethernet frame size is 1500, and bigger packets will be only sent partially. The application must care about limiting the data size. 61 | 62 | 63 | ## How to run 64 | 65 | You first need to compile everything. To compile, run `make`. Once compiled, all executables will be inside the folder `build`. 66 | 67 | To load a kernel module type `sudo insmod module_name.ko parameters`.
68 | To unload it, `sudo rmmod module_name.ko`.
69 | `module_name` is the name of the module. 70 | 71 | To run an user space application type `sudo ./application_name`. 72 | 73 | Note that both kernel modules and user space applications need `sudo` privileges in order to work. 74 | 75 | ### Parameters 76 | 77 | Each module and user application has its parameters. Parameters info of kernel modules can be seen by calling `modinfo module_name.ko`. Parameters info of applications can be seen by calling the application with `-h` flag. All parameters can be inserted in any order. 78 | 79 | ### Order of execution 80 | 81 | It is recommended to firstly load all KAcceptors, then KProposers, and then KLearners.
82 | Once they all are loaded, Learner in user space can be executed, and then finally client in user space can start.
83 | 84 | 85 | ## Disclaimer 86 | 87 | As any possible kernel module, also these modules are prone to crash. 88 | In case of module crash or severe kernel panic (mouse not working, screen freezed etc.) the only thing you can do is reboot the machine. I am not responsible of any use or damage they can create. 89 | -------------------------------------------------------------------------------- /evpaxos/message.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "message.h" 29 | #include "eth.h" 30 | #include "paxos.h" 31 | #include "paxos_types_pack.h" 32 | 33 | void 34 | send_paxos_message(struct net_device* dev, eth_address* addr, 35 | paxos_message* msg) 36 | { 37 | eth_address packer[ETH_DATA_LEN]; 38 | long size_msg = msgpack_pack_paxos_message(packer, msg); 39 | 40 | eth_send(dev, addr, (uint16_t)msg->type, packer, size_msg); 41 | } 42 | 43 | void 44 | send_paxos_learner_hi(struct net_device* dev, eth_address* addr) 45 | { 46 | paxos_message msg = { .type = PAXOS_LEARNER_HI }; 47 | send_paxos_message(dev, addr, &msg); 48 | paxos_log_debug("Learner: Send hi to the acceptors"); 49 | } 50 | 51 | void 52 | send_paxos_acceptor_ok(struct net_device* dev, eth_address* addr) 53 | { 54 | paxos_message msg = { .type = PAXOS_ACCEPTOR_OK }; 55 | send_paxos_message(dev, addr, &msg); 56 | paxos_log_debug("Acceptor: Send ok to the learner"); 57 | } 58 | 59 | void 60 | send_paxos_learner_del(struct net_device* dev, eth_address* addr) 61 | { 62 | paxos_message msg = { .type = PAXOS_LEARNER_DEL }; 63 | send_paxos_message(dev, addr, &msg); 64 | paxos_log_debug("Learner: Send del to the acceptors"); 65 | } 66 | 67 | void 68 | send_paxos_prepare(struct net_device* dev, eth_address* addr, paxos_prepare* pp) 69 | { 70 | 71 | paxos_message msg = { .type = PAXOS_PREPARE, .u.prepare = *pp }; 72 | 73 | send_paxos_message(dev, addr, &msg); 74 | paxos_log_debug("Proposer: Send prepare for iid %d ballot %d", pp->iid, 75 | pp->ballot); 76 | } 77 | 78 | void 79 | send_paxos_promise(struct net_device* dev, eth_address* addr, paxos_promise* p) 80 | { 81 | paxos_message msg = { .type = PAXOS_PROMISE, .u.promise = *p }; 82 | send_paxos_message(dev, addr, &msg); 83 | paxos_log_debug("Acceptor: Send promise for iid %d ballot %d", p->iid, 84 | p->ballot); 85 | } 86 | 87 | void 88 | send_paxos_accept(struct net_device* dev, eth_address* addr, paxos_accept* pa) 89 | { 90 | paxos_message msg = { .type = PAXOS_ACCEPT, .u.accept = *pa }; 91 | send_paxos_message(dev, addr, &msg); 92 | paxos_log_debug("Proposer: Send accept for iid %d ballot %d", pa->iid, 93 | pa->ballot); 94 | } 95 | 96 | void 97 | send_paxos_accepted(struct net_device* dev, eth_address* addr, 98 | paxos_accepted* p) 99 | { 100 | paxos_message msg = { .type = PAXOS_ACCEPTED, .u.accepted = *p }; 101 | send_paxos_message(dev, addr, &msg); 102 | paxos_log_debug("Acceptor: Send accepted for inst %d ballot %d", p->iid, 103 | p->ballot); 104 | } 105 | 106 | void 107 | send_paxos_preempted(struct net_device* dev, eth_address* addr, 108 | paxos_preempted* p) 109 | { 110 | paxos_message msg = { .type = PAXOS_PREEMPTED, .u.preempted = *p }; 111 | send_paxos_message(dev, addr, &msg); 112 | paxos_log_debug("Acceptor Send preempted for inst %d ballot %d", p->iid, 113 | p->ballot); 114 | } 115 | 116 | void 117 | send_paxos_repeat(struct net_device* dev, eth_address* addr, paxos_repeat* p) 118 | { 119 | paxos_message msg = { .type = PAXOS_REPEAT, .u.repeat = *p }; 120 | send_paxos_message(dev, addr, &msg); 121 | paxos_log_debug("Learner: Send repeat for inst %d-%d", p->from, p->to); 122 | } 123 | 124 | void 125 | send_paxos_trim(struct net_device* dev, eth_address* addr, paxos_trim* t) 126 | { 127 | paxos_message msg = { .type = PAXOS_TRIM, .u.trim = *t }; 128 | send_paxos_message(dev, addr, &msg); 129 | paxos_log_debug("Learner: Send trim for inst %d", t->iid); 130 | } 131 | 132 | void 133 | paxos_submit(struct net_device* dev, eth_address* addr, char* data, int size) 134 | { 135 | paxos_message msg = { .type = PAXOS_CLIENT_VALUE, 136 | .u.client_value.value.paxos_value_len = size, 137 | .u.client_value.value.paxos_value_val = data }; 138 | send_paxos_message(dev, addr, &msg); 139 | paxos_log_debug("Client: Sent client value size data %d", size); 140 | } 141 | 142 | int 143 | recv_paxos_message(paxos_message* msg, char* msg_data, paxos_message_type proto, 144 | char* data, size_t size) 145 | { 146 | return msgpack_unpack_paxos_message(msg, msg_data, proto, data, size); 147 | } 148 | -------------------------------------------------------------------------------- /paxos/storage_mem-old.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "storage.h" 29 | #include "uthash.h" 30 | #include 31 | 32 | #ifndef HASH_FIND_IID 33 | #define HASH_FIND_IID(head, findint, out) \ 34 | HASH_FIND(hh, head, findint, sizeof(iid_t), out) 35 | #endif 36 | 37 | #ifndef HASH_ADD_IID 38 | #define HASH_ADD_IID(head, intfield, add) \ 39 | HASH_ADD(hh, head, intfield, sizeof(iid_t), add) 40 | #endif 41 | 42 | struct hash_item 43 | { 44 | iid_t iid; 45 | paxos_accepted* value; 46 | UT_hash_handle hh; 47 | }; 48 | 49 | struct mem_storage // db 50 | { 51 | iid_t trim_iid; 52 | struct hash_item* record; 53 | }; 54 | 55 | static void paxos_accepted_copy(paxos_accepted* dst, paxos_accepted* src); 56 | 57 | static struct mem_storage* 58 | mem_storage_new(int acceptor_id) 59 | { 60 | struct mem_storage* s = pmalloc(sizeof(struct mem_storage)); 61 | if (s == NULL) 62 | return s; 63 | s->trim_iid = 0; 64 | s->record = NULL; 65 | return s; 66 | } 67 | 68 | static int 69 | mem_storage_open(void* handle) 70 | { 71 | return 0; 72 | } 73 | 74 | static void 75 | mem_storage_close(void* handle) 76 | { 77 | struct mem_storage* s = handle; 78 | struct hash_item* current_hash; 79 | struct hash_item* tmp; 80 | HASH_ITER(hh, s->record, current_hash, tmp) 81 | { 82 | HASH_DEL(s->record, current_hash); 83 | paxos_accepted_free(current_hash->value); 84 | pfree(current_hash); 85 | } 86 | 87 | pfree(s); 88 | } 89 | 90 | static int 91 | mem_storage_tx_begin(void* handle) 92 | { 93 | return 0; 94 | } 95 | 96 | static int 97 | mem_storage_tx_commit(void* handle) 98 | { 99 | return 0; 100 | } 101 | 102 | static void 103 | mem_storage_tx_abort(void* handle) 104 | {} 105 | 106 | static int 107 | mem_storage_get(void* handle, iid_t iids, paxos_accepted* out) 108 | { 109 | struct mem_storage* s = handle; 110 | struct hash_item* h; 111 | HASH_FIND_IID(s->record, &iids, h); 112 | if (h == NULL) { 113 | return 0; 114 | } 115 | paxos_accepted_copy(out, h->value); 116 | return 1; 117 | } 118 | 119 | static int 120 | mem_storage_put(void* handle, paxos_accepted* acc) 121 | { 122 | struct mem_storage* s = handle; 123 | struct hash_item* a; 124 | 125 | paxos_accepted* val = pmalloc(sizeof(paxos_accepted)); 126 | if (val != NULL) { 127 | paxos_accepted_copy(val, acc); 128 | 129 | HASH_FIND_IID(s->record, &(acc->iid), a); 130 | if (a != NULL) { 131 | paxos_accepted_free(a->value); 132 | a->value = val; 133 | a->iid = acc->iid; 134 | } else { 135 | a = pmalloc(sizeof(struct hash_item)); 136 | if (a != NULL) { 137 | a->value = val; 138 | a->iid = acc->iid; 139 | HASH_ADD_IID(s->record, iid, a); 140 | } 141 | } 142 | } 143 | 144 | return 0; 145 | } 146 | 147 | static int 148 | mem_storage_trim(void* handle, iid_t iid) 149 | { 150 | struct mem_storage* s = handle; 151 | struct hash_item * hash_el, *tmp; 152 | HASH_ITER(hh, s->record, hash_el, tmp) 153 | { 154 | if (hash_el->iid <= (int)iid) { 155 | HASH_DEL(s->record, hash_el); 156 | paxos_accepted_free(hash_el->value); 157 | pfree(hash_el); 158 | } 159 | } 160 | s->trim_iid = iid; 161 | return 0; 162 | } 163 | 164 | static iid_t 165 | mem_storage_get_trim_instance(void* handle) 166 | { 167 | struct mem_storage* s = handle; 168 | return s->trim_iid; 169 | } 170 | 171 | static void 172 | paxos_accepted_copy(paxos_accepted* dst, paxos_accepted* src) 173 | { 174 | memcpy(dst, src, sizeof(paxos_accepted)); 175 | if (dst->value.paxos_value_len > 0) { 176 | dst->value.paxos_value_val = pmalloc(src->value.paxos_value_len); 177 | memcpy(dst->value.paxos_value_val, src->value.paxos_value_val, 178 | src->value.paxos_value_len); 179 | } 180 | } 181 | 182 | void 183 | storage_init_mem(struct storage* s, int acceptor_id) 184 | { 185 | s->handle = mem_storage_new(acceptor_id); 186 | s->api.open = mem_storage_open; 187 | s->api.close = mem_storage_close; 188 | s->api.tx_begin = mem_storage_tx_begin; 189 | s->api.tx_commit = mem_storage_tx_commit; 190 | s->api.tx_abort = mem_storage_tx_abort; 191 | s->api.get = mem_storage_get; 192 | s->api.put = mem_storage_put; 193 | s->api.trim = mem_storage_trim; 194 | s->api.get_trim_instance = mem_storage_get_trim_instance; 195 | } 196 | -------------------------------------------------------------------------------- /kpaxos/user_eth.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "paxos_types.h" 15 | #include "user_eth.h" 16 | 17 | static uint8_t if_addr[ETH_ALEN]; 18 | static int if_index; 19 | 20 | static void 21 | serialize_int_to_big(uint32_t n, unsigned char** buffer) 22 | { 23 | unsigned char* res = (unsigned char*)&n; 24 | (*buffer)[0] = res[3]; 25 | (*buffer)[1] = res[2]; 26 | (*buffer)[2] = res[1]; 27 | (*buffer)[3] = res[0]; 28 | *buffer += sizeof(uint32_t); 29 | } 30 | 31 | static void 32 | cp_int_packet(uint32_t n, unsigned char** buffer) 33 | { 34 | memcpy(*buffer, &n, sizeof(uint32_t)); 35 | *buffer += sizeof(uint32_t); 36 | } 37 | 38 | // returns 1 if architecture is little endian, 0 in case of big endian. 39 | static int 40 | check_for_endianness() 41 | { 42 | unsigned int x = 1; 43 | char* c = (char*)&x; 44 | return (int)*c; 45 | } 46 | 47 | int 48 | str_to_mac(const char* str, uint8_t daddr[ETH_ALEN]) 49 | { 50 | int values[6], i; 51 | if (6 == sscanf(str, "%x:%x:%x:%x:%x:%x", &values[0], &values[1], &values[2], 52 | &values[3], &values[4], &values[5])) { 53 | /* convert to uint8_t */ 54 | for (i = 0; i < 6; ++i) 55 | daddr[i] = (uint8_t)values[i]; 56 | return 1; 57 | } 58 | return 0; 59 | } 60 | 61 | int 62 | mac_to_str(uint8_t daddr[ETH_ALEN], char* str) 63 | { 64 | sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x\n", daddr[0], daddr[1], daddr[2], 65 | daddr[3], daddr[4], daddr[5]); 66 | return 1; 67 | } 68 | 69 | size_t 70 | eth_recmsg(struct eth_connection* ethop, uint8_t sndr_addr[ETH_ALEN], 71 | char* rmsg, size_t len) 72 | { 73 | char buf[ETH_FRAME_LEN] = { 0 }; 74 | struct ether_header* eh = (struct ether_header*)buf; 75 | ssize_t received; 76 | 77 | received = recvfrom(ethop->socket, buf, ETH_FRAME_LEN, 0, NULL, NULL); 78 | if (received <= 0) { 79 | perror("recvfrom()"); 80 | return 0; 81 | } 82 | 83 | if (sndr_addr) 84 | memcpy(sndr_addr, eh->ether_shost, ETH_ALEN); 85 | 86 | received -= sizeof(*eh); 87 | received -= sizeof(PAXOS_CLIENT_VALUE); 88 | 89 | // if message too big than given buffer, cut it 90 | if (received > len) 91 | received = len; 92 | 93 | memcpy(rmsg, buf + sizeof(*eh) + sizeof(PAXOS_CLIENT_VALUE), received); 94 | return received; 95 | } 96 | 97 | void 98 | eth_sendmsg(struct eth_connection* ethop, uint8_t dest_addr[ETH_ALEN], 99 | void* clv, size_t size) 100 | { 101 | uint32_t len = size; 102 | unsigned char* tmp; 103 | char* value = (char*)clv; 104 | unsigned char buf[ETH_FRAME_LEN] = { 0 }; 105 | size_t send_len; 106 | struct ether_header* eh; 107 | struct sockaddr_ll sock_addr; 108 | 109 | /* Construct ethernet header. */ 110 | eh = (struct ether_header*)buf; 111 | memcpy(eh->ether_shost, if_addr, ETH_ALEN); 112 | memcpy(eh->ether_dhost, dest_addr, ETH_ALEN); 113 | eh->ether_type = htons(PAXOS_CLIENT_VALUE); 114 | send_len = sizeof(*eh); 115 | 116 | /* Fill the packet data. */ 117 | if (len + send_len >= ETH_FRAME_LEN) 118 | len = ETH_FRAME_LEN - send_len - sizeof(unsigned int); 119 | 120 | tmp = &(buf[send_len]); 121 | if (check_for_endianness()) { 122 | // Machine is little endian, transform the packet data from little 123 | // to big endian 124 | serialize_int_to_big(len, &tmp); 125 | } else { 126 | cp_int_packet(len, &tmp); 127 | } 128 | memcpy(tmp, value, len); 129 | send_len += len; 130 | send_len += (sizeof(unsigned int)); 131 | 132 | /* Fill the destination address and send it. */ 133 | sock_addr.sll_ifindex = if_index; 134 | sock_addr.sll_halen = ETH_ALEN; 135 | memcpy(sock_addr.sll_addr, dest_addr, ETH_ALEN); 136 | 137 | if (sendto(ethop->socket, buf, send_len, 0, (struct sockaddr*)&sock_addr, 138 | sizeof(sock_addr)) < 0) { 139 | perror("sendto()"); 140 | } else { 141 | char arr[20]; 142 | mac_to_str(dest_addr, arr); 143 | // printf("Sent to %s", arr); 144 | } 145 | } 146 | 147 | int 148 | eth_listen(struct eth_connection* ethop) 149 | { 150 | struct ifreq ifr; 151 | int s; 152 | 153 | memset(&ifr, 0, sizeof(ifr)); 154 | strncpy(ifr.ifr_name, ethop->if_name, IFNAMSIZ - 1); 155 | 156 | /* Set interface to promiscuous mode. */ 157 | if (ioctl(ethop->socket, SIOCGIFFLAGS, &ifr) < 0) { 158 | perror("Error setting the SIOCGIFFLAGS"); 159 | close(ethop->socket); 160 | return 1; 161 | } 162 | ifr.ifr_flags |= IFF_PROMISC; 163 | if (ioctl(ethop->socket, SIOCSIFFLAGS, &ifr) < 0) { 164 | perror("Error setting the SIOCSIFFLAGS"); 165 | close(ethop->socket); 166 | return 1; 167 | } 168 | 169 | /* Allow the socket to be reused. */ 170 | s = 1; 171 | if (setsockopt(ethop->socket, SOL_SOCKET, SO_REUSEADDR, &s, sizeof(s)) < 0) { 172 | perror("Error setting the socket as reused"); 173 | close(ethop->socket); 174 | return 1; 175 | } 176 | 177 | /* Bind to device. */ 178 | if (setsockopt(ethop->socket, SOL_SOCKET, SO_BINDTODEVICE, ethop->if_name, 179 | IFNAMSIZ - 1) < 0) { 180 | perror("Error binding the device"); 181 | close(ethop->socket); 182 | return 1; 183 | } 184 | 185 | return 0; 186 | } 187 | 188 | int 189 | eth_init(struct eth_connection* ethop) 190 | { 191 | 192 | struct ifreq ifr; 193 | ethop->socket = socket(AF_PACKET, SOCK_RAW, htons(PAXOS_CLIENT_VALUE)); 194 | 195 | if (ethop->socket < 0) { 196 | printf("Socket not working, maybe you are not using sudo?\n"); 197 | return 1; 198 | } 199 | 200 | /* Get the index number and MAC address of ethernet interface. */ 201 | memset(&ifr, 0, sizeof(ifr)); 202 | strncpy(ifr.ifr_name, ethop->if_name, IFNAMSIZ - 1); 203 | if (ioctl(ethop->socket, SIOCGIFINDEX, &ifr) < 0) { 204 | perror("Error getting the interface index"); 205 | return 1; 206 | } 207 | if_index = ifr.ifr_ifindex; 208 | if (ioctl(ethop->socket, SIOCGIFHWADDR, &ifr) < 0) { 209 | perror("Error getting the interface MAC address"); 210 | return 1; 211 | } 212 | memcpy(if_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); 213 | return 0; 214 | } 215 | -------------------------------------------------------------------------------- /kpaxos/user_client.c: -------------------------------------------------------------------------------- 1 | #include "user_eth.h" 2 | #include "user_levent.h" 3 | #include "user_stats.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static int use_chardevice = 0, use_socket = 0; 13 | static int stop = 1; 14 | static struct client* client; 15 | 16 | void 17 | stop_execution(int sig) 18 | { 19 | if (stop) { 20 | int buff[2]; 21 | buff[0] = CLOSE_CONN; 22 | buff[1] = client->learner_id; 23 | eth_sendmsg(&client->ethop, client->learner_addr, buff, sizeof(buff)); 24 | } 25 | stop = 0; 26 | } 27 | 28 | void 29 | timercallback(int sig) 30 | { 31 | on_stats(client); 32 | if (stop) 33 | alarm(1); 34 | } 35 | 36 | static void 37 | unpack_message(struct client* cl, ssize_t len) 38 | { 39 | struct user_msg* mess = (struct user_msg*)cl->ethop.rec_buffer; 40 | struct client_value* val = (struct client_value*)mess->value; 41 | int id = val->client_id - cl->id; 42 | 43 | if (id >= 0 && id < cl->nclients) { 44 | update_stats(&cl->stats, val->t, cl->value_size); 45 | // printf("Client %d received value %.16s with %zu bytes\n", val->client_id, 46 | // val->value, val->size); 47 | client_submit_value(cl, val->client_id); 48 | } 49 | } 50 | 51 | static void 52 | read_file(struct client* cl) 53 | { 54 | 55 | ssize_t len = read(cl->fileop.fd, cl->ethop.rec_buffer, ETH_DATA_LEN); 56 | if (len == 0) { 57 | printf("Stopped by kernel module\n"); 58 | stop = 0; 59 | } 60 | unpack_message(cl, len); 61 | } 62 | 63 | void 64 | read_socket(struct client* cl) 65 | { 66 | int* buff = (int*)cl->ethop.rec_buffer; 67 | static int set_learner = 1; 68 | ssize_t len; 69 | 70 | len = eth_recmsg(&cl->ethop, NULL, cl->ethop.rec_buffer, ETH_DATA_LEN); 71 | if (len <= 0) 72 | return; 73 | 74 | if (set_learner && buff[0] == OK) { 75 | cl->learner_id = buff[1]; 76 | printf("Connected with learner! id %d\n", buff[1]); 77 | for (int i = 0; i < cl->nclients; i++) { 78 | client_submit_value(cl, i + cl->id); 79 | } 80 | set_learner = 0; 81 | return; 82 | } 83 | unpack_message(cl, len); 84 | } 85 | 86 | static void 87 | make_client(struct client* cl) 88 | { 89 | 90 | struct pollfd pol; 91 | struct timeval seed; 92 | int fileid; 93 | char file_name[128]; 94 | void (*callback)(struct client * cl); 95 | 96 | // ethernet for proposer 97 | if (eth_init(&cl->ethop)) 98 | goto cleanup; 99 | 100 | if (eth_listen(&cl->ethop)) 101 | goto cleanup; 102 | 103 | pol.events = POLLIN; 104 | 105 | if (use_socket) { 106 | int buff[3]; 107 | buff[0] = OPEN_CONN; 108 | buff[1] = cl->id; 109 | buff[2] = cl->nclients + cl->id; 110 | eth_sendmsg(&cl->ethop, cl->learner_addr, buff, sizeof(buff)); 111 | pol.fd = cl->ethop.socket; 112 | callback = read_socket; 113 | } else { // chardevice 114 | if (open_file(&cl->fileop)) 115 | goto cleanup; 116 | 117 | for (int i = 0; i < cl->nclients; i++) { 118 | client_submit_value(cl, i + cl->id); 119 | } 120 | pol.fd = cl->fileop.fd; 121 | callback = read_file; 122 | } 123 | stats_init(); 124 | 125 | while (stop) { 126 | poll(&pol, 1, -1); 127 | if (pol.revents == POLLIN) { 128 | callback(cl); 129 | } 130 | } 131 | 132 | stats_print(); 133 | gettimeofday(&seed, NULL); 134 | srand(seed.tv_usec); 135 | fileid = rand(); 136 | fileid &= 0xffffff; 137 | sprintf(file_name, "stats-%3.3dclients-%d.txt", cl->nclients, fileid); 138 | stats_persist(file_name); 139 | stats_destroy(); 140 | 141 | cleanup: 142 | client_free(cl); 143 | } 144 | 145 | static void 146 | check_args(int argc, char* argv[], struct client* cl, char** path) 147 | { 148 | int opt = 0, idx = 0; 149 | 150 | static struct option options[] = { 151 | { "if_name", required_argument, 0, 'i' }, 152 | { "proposer-id", required_argument, 0, 'p' }, 153 | { "learner-addr", required_argument, 0, 'l' }, 154 | { "chardev_id", required_argument, 0, 'c' }, 155 | { "value-size", required_argument, 0, 'v' }, 156 | { "outstanding", required_argument, 0, 'o' }, 157 | { "id", required_argument, 0, 'd' }, 158 | { "nclients", required_argument, 0, 'n' }, 159 | { "file", required_argument, 0, 'f' }, 160 | { "help", no_argument, 0, 'h' }, 161 | { 0, 0, 0, 0 } 162 | }; 163 | 164 | while ((opt = getopt_long(argc, argv, "i:p:c:l:v:o:d:n:f:h", options, 165 | &idx)) != -1) { 166 | switch (opt) { 167 | case 'i': 168 | cl->ethop.if_name = optarg; 169 | break; 170 | case 'p': 171 | cl->prop_id = atoi(optarg); 172 | break; 173 | case 'c': 174 | use_chardevice = 1; 175 | cl->fileop.char_device_id = atoi(optarg); 176 | break; 177 | case 'l': 178 | use_socket = 1; 179 | str_to_mac(optarg, cl->learner_addr); 180 | break; 181 | case 'v': 182 | cl->value_size = atoi(optarg); 183 | break; 184 | case 'o': 185 | cl->outstanding = atoi(optarg); 186 | break; 187 | case 'd': 188 | cl->id = atoi(optarg); 189 | break; 190 | case 'n': 191 | cl->nclients = atoi(optarg); 192 | break; 193 | case 'f': 194 | *path = optarg; 195 | break; 196 | default: 197 | usage(argv[0], 1); 198 | } 199 | } 200 | } 201 | 202 | int 203 | main(int argc, char* argv[]) 204 | { 205 | struct client* cl = client_new(); 206 | char* path = "./paxos.conf"; 207 | 208 | client = cl; 209 | 210 | check_args(argc, argv, cl, &path); 211 | cl->nclients_time = malloc(sizeof(struct timeval) * cl->nclients); 212 | memset(cl->nclients_time, 0, sizeof(struct timeval) * cl->nclients); 213 | cl->send_buffer_len = sizeof(struct client_value) + cl->value_size; 214 | 215 | prepare_clval(cl); 216 | 217 | if (find_proposer(cl, path)) { 218 | printf("Wrong proposer id %d\n", cl->prop_id); 219 | goto exit_err; 220 | } 221 | print_settings(cl); 222 | 223 | if ((use_chardevice ^ use_socket) == 0) { 224 | printf("Either use chardevice or connect remotely to a learner\n"); 225 | goto exit_err; 226 | } 227 | 228 | signal(SIGINT, stop_execution); 229 | signal(SIGALRM, timercallback); 230 | alarm(1); 231 | make_client(cl); 232 | 233 | return 0; 234 | 235 | exit_err: 236 | free(cl->nclients_time); 237 | free(cl); 238 | usage(argv[0], 1); 239 | exit(1); 240 | } 241 | -------------------------------------------------------------------------------- /kpaxos/kernel_device.c: -------------------------------------------------------------------------------- 1 | #include "kernel_device.h" 2 | #include "eth.h" 3 | #include "kernel_client.h" 4 | #include "paxos.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define BUFFER_SIZE 100000 11 | static struct mutex char_mutex; 12 | // static struct mutex buffer_mutex; 13 | 14 | // The device-driver class struct pointer 15 | static struct class* charClass = NULL; 16 | // The device-driver device struct pointer 17 | static struct device* charDevice = NULL; 18 | static wait_queue_head_t access_wait; 19 | static char * de_name, *clas_name; 20 | static int majorNumber, working, current_buf = 0, first_buf = 0; 21 | static struct user_msg** msg_buf; 22 | static atomic_t used_buf; 23 | 24 | struct file_operations fops = { 25 | .owner = THIS_MODULE, 26 | .open = kdev_open, 27 | .read = kdev_read, 28 | .write = kdev_write, 29 | .release = kdev_release, 30 | .poll = kdev_poll, 31 | }; 32 | 33 | static void 34 | paxerr(char* err) 35 | { 36 | paxos_log_error("Device Char: failed to %s", err); 37 | // working = 0; 38 | } 39 | 40 | int 41 | kdev_open(struct inode* inodep, struct file* filep) 42 | { 43 | if (!mutex_trylock(&char_mutex)) { 44 | paxos_log_error("Device char: Device used by another process"); 45 | return -EBUSY; 46 | } 47 | return 0; 48 | } 49 | 50 | void 51 | kset_message(char* msg, size_t size) 52 | { 53 | if (atomic_read(&used_buf) >= BUFFER_SIZE) { 54 | if (printk_ratelimit()) 55 | paxos_log_error("Buffer is full! Lost a value"); 56 | } 57 | 58 | msg_buf[current_buf]->size = size; 59 | memcpy(msg_buf[current_buf]->value, msg, size); 60 | current_buf = (current_buf + 1) % BUFFER_SIZE; 61 | atomic_inc(&used_buf); 62 | wake_up_interruptible(&access_wait); 63 | } 64 | 65 | // returns 0 if it has to stop, >0 when it reads something, and <0 on error 66 | ssize_t 67 | kdev_read(struct file* filep, char* buffer, size_t len, loff_t* offset) 68 | { 69 | int error_count; 70 | 71 | if (!working) { 72 | return 0; 73 | } 74 | 75 | atomic_dec(&used_buf); 76 | size_t llen = sizeof(struct user_msg) + msg_buf[first_buf]->size; 77 | error_count = copy_to_user(buffer, (char*)msg_buf[first_buf], llen); 78 | 79 | if (error_count != 0) { 80 | paxerr("send fewer characters to the user"); 81 | return -1; 82 | } else 83 | first_buf = (first_buf + 1) % BUFFER_SIZE; 84 | 85 | return llen; 86 | } 87 | 88 | ssize_t 89 | kdev_write(struct file* filep, const char* buffer, size_t len, loff_t* offset) 90 | { 91 | if (working == 0) 92 | return -1; 93 | 94 | return len; 95 | } 96 | 97 | unsigned int 98 | kdev_poll(struct file* file, poll_table* wait) 99 | { 100 | poll_wait(file, &access_wait, wait); 101 | if (atomic_read(&used_buf) > 0) 102 | return POLLIN; 103 | 104 | return 0; 105 | } 106 | 107 | int 108 | kdev_release(struct inode* inodep, struct file* filep) 109 | { 110 | mutex_unlock(&char_mutex); 111 | // LOG_INFO("Messages left %d", atomic_read(&used_buf)); 112 | atomic_set(&used_buf, 0); 113 | current_buf = 0; 114 | first_buf = 0; 115 | LOG_INFO("Device Char: Device successfully closed"); 116 | return 0; 117 | } 118 | 119 | static void 120 | allocate_name(char** dest, char* name, int id) 121 | { 122 | size_t len = strlen(name) + 1; 123 | *dest = pmalloc(len + 1); 124 | memcpy(*dest, name, len); 125 | (*dest)[len - 1] = id + '0'; 126 | (*dest)[len] = '\0'; 127 | } 128 | 129 | static void 130 | allocate_name_folder(char** dest, char* name, int id) 131 | { 132 | char* folder = "paxos"; 133 | size_t f_len = strlen(folder); 134 | size_t len = strlen(name); 135 | *dest = pmalloc(f_len + len + 3); 136 | memcpy(*dest, folder, f_len); 137 | (*dest)[f_len] = '/'; 138 | (*dest)[f_len + 1] = '\0'; 139 | strcat(*dest, name); 140 | (*dest)[f_len + len + 1] = id + '0'; 141 | (*dest)[f_len + len + 2] = '\0'; 142 | } 143 | 144 | static int 145 | major_number(int id, char* name) 146 | { 147 | allocate_name_folder(&de_name, name, id); 148 | majorNumber = register_chrdev(0, de_name, &fops); 149 | if (majorNumber < 0) { 150 | paxerr("register major number"); 151 | return majorNumber; 152 | } 153 | paxos_log_debug("Device Char: Device Char %s registered correctly with major" 154 | " number %d", 155 | de_name, majorNumber); 156 | return 0; 157 | } 158 | 159 | static int 160 | reg_dev_class(int id, char* name) 161 | { 162 | allocate_name(&clas_name, name, id); 163 | charClass = class_create(THIS_MODULE, clas_name); 164 | if (IS_ERR(charClass)) { 165 | unregister_chrdev(majorNumber, de_name); 166 | paxerr("register device class"); 167 | return -1; 168 | } 169 | paxos_log_debug("Device Char: device class %s registered correctly", 170 | clas_name); 171 | return 0; 172 | } 173 | 174 | static int 175 | reg_char_class(void) 176 | { 177 | charDevice = 178 | device_create(charClass, NULL, MKDEV(majorNumber, 0), NULL, de_name); 179 | if (IS_ERR(charDevice)) { 180 | class_destroy(charClass); 181 | unregister_chrdev(majorNumber, de_name); 182 | paxerr("create the device"); 183 | return -1; 184 | } 185 | return 0; 186 | } 187 | 188 | int 189 | kdevchar_init(int id, char* name) 190 | { 191 | if (name == NULL) 192 | return 0; 193 | paxos_log_debug("Client: Initializing the Device Char"); 194 | working = 1; 195 | 196 | // Register major number 197 | if (major_number(id, name) < 0) 198 | return -1; 199 | 200 | // Register the device class 201 | if (reg_dev_class(id, name) < 0) 202 | return -1; 203 | 204 | // Register the device driver 205 | if (reg_char_class() < 0) 206 | return -1; 207 | 208 | msg_buf = vmalloc(sizeof(struct user_msg*) * BUFFER_SIZE); 209 | for (size_t i = 0; i < BUFFER_SIZE; i++) { 210 | msg_buf[i] = vmalloc(sizeof(struct user_msg) + ETH_DATA_LEN); 211 | } 212 | 213 | mutex_init(&char_mutex); 214 | init_waitqueue_head(&access_wait); 215 | atomic_set(&used_buf, 0); 216 | paxos_log_debug("Device Char: device class created correctly"); 217 | return 0; 218 | } 219 | 220 | void 221 | kdevchar_exit(void) 222 | { 223 | working = 0; 224 | atomic_inc(&used_buf); 225 | wake_up_interruptible(&access_wait); 226 | mutex_destroy(&char_mutex); 227 | device_destroy(charClass, MKDEV(majorNumber, 0)); // remove the device 228 | class_unregister(charClass); // unregister the device class 229 | class_destroy(charClass); // remove the device class 230 | 231 | for (int i = 0; i < BUFFER_SIZE; i++) { 232 | vfree(msg_buf[i]); 233 | } 234 | vfree(msg_buf); 235 | 236 | pfree(de_name); 237 | pfree(clas_name); 238 | unregister_chrdev(majorNumber, de_name); // unregister the major number 239 | paxos_log_debug(KERN_INFO "Device Char: Unloaded\n"); 240 | } 241 | -------------------------------------------------------------------------------- /evpaxos/include/evpaxos/paxos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #ifndef _EVPAXOS_H_ 29 | #define _EVPAXOS_H_ 30 | 31 | #include 32 | #include 33 | 34 | #include "common.h" 35 | 36 | #ifdef __cplusplus 37 | extern "C" 38 | { 39 | #endif 40 | 41 | struct evlearner; 42 | struct evproposer; 43 | struct evacceptor; 44 | struct evpaxos_replica; 45 | 46 | /** 47 | * When starting a learner you must pass a callback to be invoked whenever 48 | * a value has been learned. 49 | */ 50 | typedef void (*deliver_function)(unsigned int, char* value, size_t size, 51 | void* arg); 52 | 53 | /** 54 | * Create a Paxos replica, consisting of a collocated Acceptor, Proposer, 55 | * and Learner. 56 | * 57 | * @param id the id of the replica 58 | * @param config path a paxos config file 59 | * @param cb the callback function to be called whenever the learner delivers. 60 | * This paramater may be NULL, in which case no learner is initialized. 61 | * @param arg an optional argument that is passed to the callback 62 | * @param base the underlying event_base to be used 63 | * 64 | * @return a new evpaxos_replica on success, or NULL on failure. 65 | * 66 | * @see evpaxos_replica_free() 67 | */ 68 | struct evpaxos_replica* evpaxos_replica_init(int id, deliver_function cb, 69 | void* arg, char* if_name, 70 | char* path); 71 | 72 | /** 73 | * Destroy a Paxos replica and free all its memory. 74 | * 75 | * @param replica a evpaxos_replica to be freed 76 | */ 77 | void evpaxos_replica_free(struct evpaxos_replica* replica); 78 | 79 | /** 80 | * Set the starting instance id of the given replica. 81 | * The replica will call the delivery function for instances larger than the 82 | * given instance id. 83 | * 84 | * @param iid the starting instance id 85 | */ 86 | void evpaxos_replica_set_instance_id(struct evpaxos_replica* replica, 87 | unsigned iid); 88 | 89 | /** 90 | * Send a trim message to all acceptors/replicas. Acceptors will trim their 91 | * log up the the given instance id. 92 | * 93 | * @param iid trim instance id 94 | */ 95 | void evpaxos_replica_send_trim(struct evpaxos_replica* replica, unsigned iid); 96 | 97 | /** 98 | * Used by replicas to submit values. 99 | */ 100 | // void evpaxos_replica_submit(struct evpaxos_replica* replica, 101 | // char* value, int size); 102 | 103 | /** 104 | * Returns the number of replicas in the configuration. 105 | */ 106 | int evpaxos_replica_count(struct evpaxos_replica* replica); 107 | 108 | /** 109 | * Initializes a learner with a given config file, a deliver callback, 110 | * an optional argument to that is passed to the callback, and 111 | * a libevent event_base. 112 | */ 113 | struct evlearner* evlearner_init(deliver_function f, void* arg, char* if_name, 114 | char* path, int isclient); 115 | 116 | /** 117 | * Release the memory allocated by the learner 118 | */ 119 | void evlearner_free(struct evlearner* l); 120 | 121 | /** 122 | * Set the starting instance id of the given learner. 123 | * The learner will call the delivery function for instances larger than the 124 | * given instance id. 125 | * 126 | * @param iid the starting instance id 127 | */ 128 | void evlearner_set_instance_id(struct evlearner* l, unsigned iid); 129 | 130 | /** 131 | * Send a trim message to all acceptors/replicas. Acceptors will trim their 132 | * log up the the given instance id. 133 | * 134 | * @param iid trim instance id 135 | */ 136 | void evlearner_send_trim(struct evlearner* l, unsigned iid); 137 | 138 | /** 139 | * Initializes a acceptor with a given id (which MUST be unique), 140 | * a config file and a libevent event_base. 141 | */ 142 | struct evacceptor* evacceptor_init(int id, char* if_name, char* path); 143 | 144 | /** 145 | * Frees the memory allocated by the acceptor. 146 | * This will also cleanly close the * underlying storage. 147 | */ 148 | void evacceptor_free(struct evacceptor* a); 149 | 150 | /** 151 | * Initializes a proposer with a given ID (which MUST be unique), 152 | * a config file and a libevent event_base. 153 | * 154 | * @param id a unique identifier, must be in the range 155 | * [0...(MAX_N_OF_PROPOSERS-1)] 156 | */ 157 | struct evproposer* evproposer_init(int id, char* if_name, char* path); 158 | 159 | /** 160 | * Release the memory allocated by the proposer 161 | */ 162 | void evproposer_free(struct evproposer* p); 163 | 164 | /** 165 | * This is a hint to the proposer to start from the given instance id. 166 | * 167 | * @param iid the starting instance id 168 | */ 169 | void evproposer_set_instance_id(struct evproposer* p, unsigned iid); 170 | 171 | /** 172 | * Used by clients to submit values to proposers. 173 | */ 174 | void paxos_submit(struct net_device* dev, eth_address* addr, char* data, 175 | int size); 176 | 177 | #ifdef __cplusplus 178 | } 179 | #endif 180 | 181 | #endif 182 | -------------------------------------------------------------------------------- /paxos/acceptor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "acceptor.h" 29 | #include "storage.h" 30 | #include 31 | #include 32 | #include 33 | 34 | struct acceptor 35 | { 36 | int id; 37 | iid_t trim_iid; 38 | struct storage store; 39 | }; 40 | 41 | static void paxos_accepted_to_promise(paxos_accepted* acc, paxos_message* out); 42 | static void paxos_accept_to_accepted(int id, paxos_accept* acc, 43 | paxos_message* out); 44 | static void paxos_accepted_to_preempted(int id, paxos_accepted* acc, 45 | paxos_message* out); 46 | 47 | struct acceptor* 48 | acceptor_new(int id) 49 | { 50 | struct acceptor* a; 51 | a = pmalloc(sizeof(struct acceptor)); 52 | storage_init(&a->store, id); 53 | if (storage_open(&a->store) != 0) { 54 | pfree(a); 55 | return NULL; 56 | } 57 | if (storage_tx_begin(&a->store) != 0) 58 | return NULL; 59 | a->id = id; 60 | a->trim_iid = storage_get_trim_instance(&a->store); 61 | if (storage_tx_commit(&a->store) != 0) 62 | return NULL; 63 | return a; 64 | } 65 | 66 | void 67 | acceptor_free(struct acceptor* a) 68 | { 69 | storage_close(&a->store); 70 | pfree(a); 71 | } 72 | 73 | int 74 | acceptor_receive_prepare(struct acceptor* a, paxos_prepare* req, 75 | paxos_message* out) 76 | { 77 | paxos_accepted acc; 78 | if (req->iid <= a->trim_iid) 79 | return 0; 80 | memset(&acc, 0, sizeof(paxos_accepted)); 81 | if (storage_tx_begin(&a->store) != 0) 82 | return 0; 83 | int found = storage_get_record(&a->store, req->iid, &acc); 84 | if (!found || acc.ballot <= req->ballot) { 85 | acc.aid = a->id; 86 | acc.iid = req->iid; 87 | acc.ballot = req->ballot; 88 | if (storage_put_record(&a->store, &acc) != 0) { 89 | storage_tx_abort(&a->store); 90 | return 0; 91 | } 92 | } 93 | if (storage_tx_commit(&a->store) != 0) 94 | return 0; 95 | paxos_accepted_to_promise(&acc, out); 96 | return 1; 97 | } 98 | 99 | int 100 | acceptor_receive_accept(struct acceptor* a, paxos_accept* req, 101 | paxos_message* out) 102 | { 103 | paxos_accepted acc; 104 | if (req->iid <= a->trim_iid) 105 | return 0; 106 | memset(&acc, 0, sizeof(paxos_accepted)); 107 | if (storage_tx_begin(&a->store) != 0) 108 | return 0; 109 | int found = storage_get_record(&a->store, req->iid, &acc); 110 | if (!found || acc.ballot <= req->ballot) { 111 | paxos_accept_to_accepted(a->id, req, out); 112 | if (storage_put_record(&a->store, &(out->u.accepted)) != 0) { 113 | storage_tx_abort(&a->store); 114 | return 0; 115 | } 116 | } else { 117 | paxos_accepted_to_preempted(a->id, &acc, out); 118 | } 119 | if (storage_tx_commit(&a->store) != 0) 120 | return 0; 121 | paxos_accepted_destroy(&acc); 122 | return 1; 123 | } 124 | 125 | int 126 | acceptor_receive_repeat(struct acceptor* a, iid_t iid, paxos_accepted* out) 127 | { 128 | memset(out, 0, sizeof(paxos_accepted)); 129 | if (storage_tx_begin(&a->store) != 0) 130 | return 0; 131 | int found = storage_get_record(&a->store, iid, out); 132 | if (storage_tx_commit(&a->store) != 0) 133 | return 0; 134 | return found && (out->value.paxos_value_len > 0); 135 | } 136 | 137 | int 138 | acceptor_receive_trim(struct acceptor* a, paxos_trim* trim) 139 | { 140 | if (trim->iid <= a->trim_iid) 141 | return 0; 142 | a->trim_iid = trim->iid; 143 | if (storage_tx_begin(&a->store) != 0) 144 | return 0; 145 | storage_trim(&a->store, trim->iid); 146 | if (storage_tx_commit(&a->store) != 0) 147 | return 0; 148 | return 1; 149 | } 150 | 151 | void 152 | acceptor_set_current_state(struct acceptor* a, paxos_acceptor_state* state) 153 | { 154 | state->aid = a->id; 155 | state->trim_iid = a->trim_iid; 156 | } 157 | 158 | static void 159 | paxos_accepted_to_promise(paxos_accepted* acc, paxos_message* out) 160 | { 161 | out->type = PAXOS_PROMISE; 162 | out->u.promise = (paxos_promise){ acc->aid, 163 | acc->iid, 164 | acc->ballot, 165 | acc->value_ballot, 166 | { acc->value.paxos_value_len, 167 | acc->value.paxos_value_val } }; 168 | } 169 | 170 | static void 171 | paxos_accept_to_accepted(int id, paxos_accept* acc, paxos_message* out) 172 | { 173 | char* value = NULL; 174 | int value_size = acc->value.paxos_value_len; 175 | if (value_size > 0) { 176 | value = pmalloc(value_size); 177 | memcpy(value, acc->value.paxos_value_val, value_size); 178 | } 179 | out->type = PAXOS_ACCEPTED; 180 | out->u.accepted = 181 | (paxos_accepted){ .aid = id, 182 | .iid = acc->iid, 183 | .promise_iid = 0, 184 | .ballot = acc->ballot, 185 | .value_ballot = acc->ballot, 186 | .value = (paxos_value){ value_size, value } }; 187 | } 188 | 189 | static void 190 | paxos_accepted_to_preempted(int id, paxos_accepted* acc, paxos_message* out) 191 | { 192 | out->type = PAXOS_PREEMPTED; 193 | out->u.preempted = (paxos_preempted){ id, acc->iid, acc->ballot }; 194 | } 195 | -------------------------------------------------------------------------------- /kpaxos/kclient.c: -------------------------------------------------------------------------------- 1 | #include "evpaxos_internal.h" 2 | #include "kernel_client.h" 3 | #include "stats.h" 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define TIMEOUT_US 1000000 16 | 17 | const char* MOD_NAME = "KClient"; 18 | 19 | static int proposer_id = 0; 20 | module_param(proposer_id, int, S_IRUGO); 21 | MODULE_PARM_DESC(proposer_id, "The proposer id, default 0"); 22 | 23 | static int outstanding = 1; 24 | module_param(outstanding, int, S_IRUGO); 25 | MODULE_PARM_DESC(outstanding, "The client outstanding, default 1"); 26 | 27 | static int value_size = 64; 28 | module_param(value_size, int, S_IRUGO); 29 | MODULE_PARM_DESC(value_size, "The size of the message, default 64"); 30 | 31 | static int id = 0; 32 | module_param(id, int, S_IRUGO); 33 | MODULE_PARM_DESC(id, "The client id, default 0"); 34 | 35 | static int nclients = 1; 36 | module_param(nclients, int, S_IRUGO); 37 | MODULE_PARM_DESC(nclients, "The number of virtual clients"); 38 | 39 | static char* if_name = "enp4s0"; 40 | module_param(if_name, charp, 0000); 41 | MODULE_PARM_DESC(if_name, "The interface name, default enp4s0"); 42 | 43 | static char* path = "./paxos.conf"; 44 | module_param(path, charp, S_IRUGO); 45 | MODULE_PARM_DESC(path, "The config file position, default ./paxos.conf"); 46 | 47 | struct client 48 | { 49 | struct timeval* clients_timeval; 50 | eth_address proposeradd[ETH_ALEN]; 51 | struct client_value* val; 52 | char send_buffer[ETH_DATA_LEN]; 53 | int send_buffer_len; 54 | struct stats stats; 55 | struct timer_list stats_ev; 56 | struct timeval stats_interval; 57 | struct evlearner* learner; 58 | }; 59 | 60 | static struct client* c = NULL; 61 | 62 | static long 63 | timeval_diff(struct timeval* t1, struct timeval* t2) 64 | { 65 | long us; 66 | us = (t2->tv_sec - t1->tv_sec) * 1000000; 67 | if (us < 0) 68 | return 0; 69 | us += (t2->tv_usec - t1->tv_usec); 70 | return us; 71 | } 72 | 73 | static void 74 | random_string(char* s, const int len) 75 | { 76 | int i, j; 77 | static const char alphanum[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 78 | 79 | for (i = 0, j = 0; i < len - 1; ++i, j = 0) { 80 | get_random_bytes(&j, sizeof(int)); 81 | j &= 0xffffff; 82 | s[i] = alphanum[j % (sizeof(alphanum) - 1)]; 83 | } 84 | 85 | s[len - 1] = 0; 86 | } 87 | 88 | static void 89 | client_submit_value(struct client* c, int cid) 90 | { 91 | c->val->client_id = cid; 92 | do_gettimeofday(&c->clients_timeval[cid - id]); 93 | c->val->t = c->clients_timeval[cid - id]; 94 | paxos_submit(evlearner_get_device(c->learner), c->proposeradd, c->send_buffer, 95 | c->send_buffer_len); 96 | // LOG_DEBUG("Client %d submitted value %.16s with %zu bytes, total size is 97 | // %d", 98 | // c->val->client_id, c->val->value, c->val->size, 99 | // c->send_buffer_len); 100 | } 101 | 102 | static void 103 | update_stats(struct stats* stats, struct client_value* delivered, size_t size) 104 | { 105 | struct timeval tv; 106 | do_gettimeofday(&tv); 107 | long lat = timeval_diff(&delivered->t, &tv); 108 | stats->delivered_count++; 109 | stats_add(lat); 110 | } 111 | 112 | static void 113 | check_timeout(void) 114 | { 115 | struct timeval now; 116 | do_gettimeofday(&now); 117 | for (int i = 0; i < nclients; i++) { 118 | if (timeval_diff(&c->clients_timeval[i], &now) > TIMEOUT_US) { 119 | LOG_ERROR("Client %d sent expired", i); 120 | client_submit_value(c, i + id); 121 | } 122 | } 123 | } 124 | 125 | static void 126 | on_deliver(unsigned iid, char* value, size_t size, void* arg) 127 | { 128 | struct client* c = arg; 129 | struct client_value* v = (struct client_value*)value; 130 | int clid = v->client_id; 131 | 132 | if (clid >= id && clid < id + nclients) { 133 | update_stats(&c->stats, v, size); 134 | // LOG_DEBUG( 135 | // "Client %d received value %.16s with %zu bytes, total size is %zu", 136 | // v->client_id, v->value, v->size, size); 137 | client_submit_value(c, clid); 138 | } 139 | } 140 | 141 | static void 142 | on_stats(unsigned long arg) 143 | { 144 | struct client* c = (struct client*)arg; 145 | long mbps = 146 | (c->stats.delivered_count * c->send_buffer_len * 8) / (1024 * 1024); 147 | 148 | LOG_INFO("%d val/sec, %ld Mbps", c->stats.delivered_count, mbps); 149 | memset(&c->stats, 0, sizeof(struct stats)); 150 | check_timeout(); 151 | mod_timer(&c->stats_ev, jiffies + timeval_to_jiffies(&c->stats_interval)); 152 | } 153 | 154 | void 155 | start_client(int proposer_id, int value_size) 156 | { 157 | struct evpaxos_config* conf = evpaxos_config_read(path); 158 | 159 | if (conf == NULL) { 160 | LOG_ERROR("Failed to read config file."); 161 | return; 162 | } 163 | 164 | c = pmalloc(sizeof(struct client)); 165 | c->learner = evlearner_init(on_deliver, c, if_name, path, 1); 166 | if (c->learner == NULL) { 167 | LOG_ERROR("Could not start the learner."); 168 | kfree(c); 169 | c = NULL; 170 | return; 171 | } 172 | 173 | c->clients_timeval = vmalloc(sizeof(struct timeval) * nclients); 174 | memset(c->clients_timeval, 0, sizeof(struct timeval) * nclients); 175 | memset(&c->stats, 0, sizeof(struct stats)); 176 | memcpy(c->proposeradd, evpaxos_proposer_address(conf, proposer_id), ETH_ALEN); 177 | evpaxos_config_free(conf); 178 | 179 | c->val = (struct client_value*)c->send_buffer; 180 | c->val->size = value_size; 181 | c->send_buffer_len = sizeof(struct client_value) + value_size; 182 | random_string(c->val->value, value_size); 183 | 184 | setup_timer(&c->stats_ev, on_stats, (unsigned long)c); 185 | c->stats_interval = (struct timeval){ 1, 0 }; 186 | mod_timer(&c->stats_ev, jiffies + timeval_to_jiffies(&c->stats_interval)); 187 | 188 | stats_init(); 189 | for (int i = 0; i < nclients; ++i) { 190 | client_submit_value(c, id + i); 191 | } 192 | } 193 | 194 | static int __init 195 | init_client(void) 196 | { 197 | LOG_INFO("Id: %d --- Nclients: %d", id, nclients); 198 | start_client(proposer_id, value_size); 199 | return 0; 200 | } 201 | 202 | static void __exit 203 | client_exit(void) 204 | { 205 | char file_name[128]; 206 | int id = 0; 207 | 208 | if (c != NULL) { 209 | if (c->learner) { 210 | del_timer(&c->stats_ev); 211 | evlearner_free(c->learner); 212 | } 213 | vfree(c->clients_timeval); 214 | pfree(c); 215 | } 216 | 217 | stats_print(); 218 | get_random_bytes(&id, sizeof(id)); 219 | id &= 0xffffff; 220 | sprintf(file_name, "stats-%3.3dclients-%d.txt", nclients, id); 221 | stats_persist(file_name); 222 | stats_destroy(); 223 | LOG_INFO("Module unloaded."); 224 | } 225 | 226 | module_init(init_client); 227 | module_exit(client_exit); 228 | MODULE_LICENSE("GPL"); 229 | MODULE_AUTHOR("Emanuele Giuseppe Esposito"); 230 | -------------------------------------------------------------------------------- /evpaxos/evlearner.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "evpaxos.h" 29 | #include "learner.h" 30 | #include "message.h" 31 | #include "peers.h" 32 | #include 33 | 34 | struct evlearner 35 | { 36 | struct learner* state; /* The actual learner */ 37 | deliver_function delfun; /* Delivery callback */ 38 | void* delarg; /* The argument to the delivery callback */ 39 | struct peers* acceptors; /* Connections to acceptors */ 40 | struct timer_list stats_ev; 41 | struct timeval stats_interval; 42 | }; 43 | 44 | struct net_device* 45 | evlearner_get_device(struct evlearner* ev) 46 | { 47 | return get_dev(ev->acceptors); 48 | } 49 | 50 | static inline void 51 | peer_send_repeat(struct net_device* dev, struct peer* p, void* arg) 52 | { 53 | send_paxos_repeat(dev, get_addr(p), arg); 54 | } 55 | 56 | static inline void 57 | peer_send_hi(struct net_device* dev, struct peer* p, void* arg) 58 | { 59 | send_paxos_learner_hi(dev, get_addr(p)); 60 | } 61 | 62 | void 63 | evlearner_send_hi(struct peers* p) 64 | { 65 | peers_foreach_acceptor(p, peer_send_hi, NULL); 66 | } 67 | 68 | static void 69 | evlearner_check_holes(unsigned long arg) 70 | { 71 | // paxos_log_debug("Learner: Checking holes"); 72 | 73 | paxos_repeat msg; 74 | int chunks = 10; 75 | struct evlearner* l = (struct evlearner*)arg; 76 | if (learner_has_holes(l->state, &msg.from, &msg.to)) { 77 | if ((msg.to - msg.from) > chunks) 78 | msg.to = msg.from + chunks; 79 | peers_foreach_acceptor(l->acceptors, peer_send_repeat, &msg); 80 | paxos_log_debug( 81 | "Learner: sent PAXOS_REPEAT to all acceptors, missing %d chunks", 82 | (msg.to - msg.from)); 83 | } 84 | 85 | if (peers_missing_ok(l->acceptors)) { 86 | paxos_log_debug("Missing some ok, resending"); 87 | peers_foreach_acceptor(l->acceptors, peer_send_hi, NULL); 88 | } 89 | mod_timer(&l->stats_ev, jiffies + timeval_to_jiffies(&l->stats_interval)); 90 | } 91 | 92 | static void 93 | evlearner_deliver_next_closed(struct evlearner* l) 94 | { 95 | paxos_accepted deliver; 96 | while (learner_deliver_next(l->state, &deliver)) { 97 | l->delfun(deliver.iid, deliver.value.paxos_value_val, 98 | deliver.value.paxos_value_len, l->delarg); 99 | paxos_accepted_destroy(&deliver); 100 | } 101 | } 102 | 103 | /* 104 | Called when an accept_ack is received, the learner will update it's 105 | status for that instance and afterwards check if the instance is closed 106 | */ 107 | static void 108 | evlearner_handle_accepted(paxos_message* msg, void* arg, eth_address* src) 109 | { 110 | struct evlearner* l = arg; 111 | paxos_log_debug("Learner: Received PAXOS_ACCEPTED"); 112 | learner_receive_accepted(l->state, &msg->u.accepted); 113 | evlearner_deliver_next_closed(l); 114 | } 115 | 116 | static void 117 | evlearner_handle_ok(paxos_message* msg, void* arg, eth_address* src) 118 | { 119 | paxos_log_debug("Learner: Received PAXOS_ACCEPTOR_OK\n"); 120 | struct evlearner* ev = (struct evlearner*)arg; 121 | peers_update_ok(ev->acceptors, src); 122 | } 123 | 124 | struct evlearner* 125 | evlearner_init_internal(struct evpaxos_config* config, struct peers* peers, 126 | deliver_function f, void* arg) 127 | { 128 | int acceptor_count = evpaxos_acceptor_count(config); 129 | struct evlearner* learner = pmalloc(sizeof(struct evlearner)); 130 | if (learner == NULL) 131 | return NULL; 132 | 133 | learner->delfun = f; 134 | learner->delarg = arg; 135 | learner->state = learner_new(acceptor_count); 136 | learner->acceptors = peers; 137 | 138 | peers_add_subscription(peers, PAXOS_ACCEPTED, evlearner_handle_accepted, 139 | learner); 140 | peers_add_subscription(peers, PAXOS_ACCEPTOR_OK, evlearner_handle_ok, 141 | learner); 142 | 143 | setup_timer(&learner->stats_ev, evlearner_check_holes, 144 | (unsigned long)learner); 145 | learner->stats_interval = (struct timeval){ 0, 100000 }; // 100 ms 146 | mod_timer(&learner->stats_ev, 147 | jiffies + timeval_to_jiffies(&learner->stats_interval)); 148 | return learner; 149 | } 150 | 151 | struct evlearner* 152 | evlearner_init(deliver_function f, void* arg, char* if_name, char* path, 153 | int isclient) 154 | { 155 | struct evpaxos_config* c = evpaxos_config_read(path); 156 | if (c == NULL) 157 | return NULL; 158 | 159 | if (isclient) 160 | paxos_config.learner_catch_up = 0; 161 | 162 | struct peers* peers = peers_new(c, -1, if_name); 163 | if (peers == NULL) { 164 | return NULL; 165 | } 166 | add_acceptors_from_config(peers, c); 167 | printall(peers, "Learner"); 168 | 169 | struct evlearner* l = evlearner_init_internal(c, peers, f, arg); 170 | peers_subscribe(peers); 171 | paxos_log_debug("Learner: Sent HI to all acceptors"); 172 | evlearner_send_hi(peers); 173 | evpaxos_config_free(c); 174 | return l; 175 | } 176 | 177 | void 178 | evlearner_free_internal(struct evlearner* l) 179 | { 180 | learner_free(l->state); 181 | del_timer(&l->stats_ev); 182 | pfree(l); 183 | } 184 | 185 | void 186 | evlearner_free(struct evlearner* l) 187 | { 188 | printall(l->acceptors, "LEARNER"); 189 | peers_foreach_acceptor(l->acceptors, peer_send_del, NULL); 190 | peers_free(l->acceptors); 191 | evlearner_free_internal(l); 192 | } 193 | 194 | void 195 | evlearner_set_instance_id(struct evlearner* l, unsigned iid) 196 | { 197 | learner_set_instance_id(l->state, iid); 198 | } 199 | 200 | static void 201 | peer_send_trim(struct net_device* dev, struct peer* p, void* arg) 202 | { 203 | send_paxos_trim(dev, get_addr(p), arg); 204 | } 205 | 206 | void 207 | evlearner_send_trim(struct evlearner* l, unsigned iid) 208 | { 209 | paxos_trim trim = { iid }; 210 | paxos_log_debug("Learner: Sent PAXOS_TRIM to all acceptors"); 211 | peers_foreach_acceptor(l->acceptors, peer_send_trim, &trim); 212 | } 213 | -------------------------------------------------------------------------------- /kpaxos/user_levent.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "user_eth.h" 8 | #include "user_levent.h" 9 | 10 | /* ################## common methods ################ */ 11 | void 12 | write_file(int fd, void* data, size_t size) 13 | { 14 | if (fd < 0) { 15 | return; 16 | } 17 | int ret = write(fd, data, size); 18 | if (ret < 0) { 19 | perror("Failed to write the message to the device"); 20 | } 21 | } 22 | 23 | int 24 | open_file(struct chardevice* c) 25 | { 26 | char* name = "/dev/paxos/klearner0"; 27 | size_t strl = strlen(name) + 1; 28 | char* fname = malloc(strl); 29 | memcpy(fname, name, strl); 30 | fname[strl - 2] = c->char_device_id + '0'; 31 | c->fd = open(fname, O_RDWR | O_NONBLOCK, 0); 32 | if (c->fd < 0) { 33 | perror("Failed to open the device"); 34 | return 1; 35 | } 36 | return 0; 37 | } 38 | 39 | void 40 | usage(const char* name, int client) 41 | { 42 | printf("Client Usage: %s [options] \n", name); 43 | printf("Options:\n"); 44 | printf(" %-30s%s\n", "-h, --help", "Output this message and exit"); 45 | printf(" %-30s%s\n", "-c, --chardev_id #", "Chardevice id"); 46 | printf(" %-30s%s\n", "-i, --if_name #", "Interface name (MAC)"); 47 | if (client) { 48 | printf(" %-30s%s\n", "-l, --learner-addr #", "Learner address (MAC)"); 49 | printf(" %-30s%s\n", "-p, --proposer-id #", "Proposer id"); 50 | printf(" %-30s%s\n", "-f, --file #", "config file"); 51 | printf(" %-30s%s\n", "-o, --outstanding #", 52 | "Number of outstanding client values"); 53 | printf(" %-30s%s\n", "-v, --value-size #", 54 | "Size of client value (in bytes)"); 55 | printf(" %-30s%s\n", "-d, --id #", "Starting id"); 56 | printf(" %-30s%s\n", "-n, --nclients #", 57 | "Number of virtual clients to simulate"); 58 | } 59 | 60 | exit(1); 61 | } 62 | 63 | /* ################## Server ################ */ 64 | struct connection_list 65 | { 66 | int progr_id; 67 | struct connection* head; 68 | struct connection* current; 69 | }; 70 | 71 | struct server* 72 | server_new() 73 | { 74 | struct server* p = malloc(sizeof(struct server)); 75 | memset(p, 0, sizeof(struct server)); 76 | p->ethop.socket = -1; 77 | p->fileop.fd = -1; 78 | return p; 79 | } 80 | 81 | static struct connection* 82 | new_connection(int start, int end, int id, uint8_t address[ETH_ALEN]) 83 | { 84 | struct connection* conn = malloc(sizeof(struct connection)); 85 | conn->start_id = start; 86 | conn->end_id = end; 87 | conn->next = NULL; 88 | conn->id = id; 89 | memcpy(conn->address, address, ETH_ALEN); 90 | return conn; 91 | } 92 | 93 | int 94 | add_connection(struct server* serv, int start, int end, 95 | uint8_t address[ETH_ALEN]) 96 | { 97 | struct connection_list* clist = serv->connections; 98 | struct connection* conn = 99 | new_connection(start, end, clist->progr_id, address); 100 | 101 | if (clist->head == NULL) { 102 | clist->head = conn; 103 | clist->current = conn; 104 | } else 105 | clist->current->next = conn; 106 | 107 | char arr[20]; 108 | mac_to_str(address, arr); 109 | printf("Accepted connection from client %d %s", clist->progr_id, arr); 110 | 111 | return clist->progr_id++; 112 | } 113 | 114 | void 115 | print_all_conn(struct server* serv) 116 | { 117 | struct connection_list* clist = serv->connections; 118 | struct connection* conn = clist->head; 119 | while (conn != NULL) { 120 | printf("%d -> \n", conn->id); 121 | conn = conn->next; 122 | } 123 | } 124 | 125 | struct connection* 126 | find_connection(struct server* serv, int val) 127 | { 128 | struct connection_list* clist = serv->connections; 129 | struct connection* conn = clist->head; 130 | while (conn != NULL) { 131 | if (val >= conn->start_id && val < conn->end_id) { 132 | return conn; 133 | } 134 | conn = conn->next; 135 | } 136 | return NULL; 137 | } 138 | 139 | void 140 | rem_connection(struct server* serv, int id) 141 | { 142 | struct connection_list* clist = serv->connections; 143 | struct connection* conn = clist->head; 144 | struct connection* prev_conn = NULL; 145 | while (conn != NULL) { 146 | if (id == conn->id) { 147 | if (prev_conn != NULL) 148 | prev_conn->next = conn->next; 149 | if (conn == clist->head) 150 | clist->head = conn->next; 151 | if (conn == clist->current) 152 | clist->current = prev_conn; 153 | 154 | char arr[20]; 155 | mac_to_str(conn->address, arr); 156 | printf("Closed connection with client %d %s", conn->id, arr); 157 | 158 | free(conn); 159 | return; 160 | } 161 | prev_conn = conn; 162 | conn = conn->next; 163 | } 164 | } 165 | 166 | static void 167 | rem_all_connections(struct server* serv) 168 | { 169 | struct connection_list* clist = serv->connections; 170 | struct connection* conn = clist->head; 171 | while (conn != NULL) { 172 | struct connection* tmp = conn; 173 | free(tmp); 174 | conn = conn->next; 175 | } 176 | } 177 | 178 | void 179 | new_connection_list(struct server* serv) 180 | { 181 | serv->connections = malloc(sizeof(struct connection_list)); 182 | serv->connections->head = NULL; 183 | serv->connections->current = NULL; 184 | serv->connections->progr_id = 0; 185 | } 186 | 187 | void 188 | server_free(struct server* serv) 189 | { 190 | rem_all_connections(serv); 191 | if (serv->fileop.fd >= 0) 192 | close(serv->fileop.fd); 193 | if (serv->ethop.socket >= 0) 194 | close(serv->ethop.socket); 195 | free(serv); 196 | } 197 | 198 | /* ################## Client ################ */ 199 | 200 | struct client* 201 | client_new() 202 | { 203 | struct client* cl = malloc(sizeof(struct client)); 204 | memset(cl, 0, sizeof(struct client)); 205 | cl->ethop.if_name = "enp4s0"; 206 | cl->ethop.socket = -1; 207 | cl->fileop.fd = -1; 208 | cl->value_size = 64; 209 | cl->outstanding = 1; 210 | cl->nclients = 1; 211 | return cl; 212 | } 213 | 214 | static void 215 | random_string(char* s, const int len) 216 | { 217 | int i; 218 | static const char alphanum[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 219 | for (i = 0; i < len - 1; ++i) 220 | s[i] = alphanum[rand() % (sizeof(alphanum) - 1)]; 221 | s[len - 1] = 0; 222 | } 223 | 224 | void 225 | prepare_clval(struct client* cl) 226 | { 227 | cl->val = (struct client_value*)cl->send_buffer; 228 | cl->val->size = cl->value_size; 229 | random_string(cl->val->value, cl->value_size); 230 | } 231 | 232 | void 233 | print_settings(struct client* cl) 234 | { 235 | printf("if_name %s\n", cl->ethop.if_name); 236 | char a[20]; 237 | mac_to_str(cl->prop_addr, a); 238 | printf("proposer address %s", a); 239 | mac_to_str(cl->learner_addr, a); 240 | printf("learner address %s", a); 241 | printf("id: %d ------ nclients: %d\n", cl->id, cl->nclients); 242 | } 243 | 244 | void 245 | client_free(struct client* cl) 246 | { 247 | if (cl->ethop.socket >= 0) 248 | close(cl->ethop.socket); 249 | 250 | if (cl->fileop.fd >= 0) 251 | close(cl->fileop.fd); 252 | free(cl->nclients_time); 253 | free(cl); 254 | } 255 | 256 | void 257 | client_submit_value(struct client* cl, int id) 258 | { 259 | struct client_value* val = cl->val; 260 | val->client_id = id; 261 | gettimeofday(&cl->nclients_time[id - cl->id], NULL); 262 | val->t = cl->nclients_time[id - cl->id]; 263 | eth_sendmsg(&cl->ethop, cl->prop_addr, val, cl->send_buffer_len); 264 | // printf("Client %d submitted value %.16s with %zu bytes\n", v->client_id, 265 | // v->value, v->size); 266 | } 267 | 268 | int 269 | find_proposer(struct client* cl, char* path) 270 | { 271 | FILE* f; 272 | int id; 273 | char addr[20]; 274 | char line[512]; 275 | char* l; 276 | 277 | if ((f = fopen(path, "r")) == NULL) { 278 | perror("fopen"); 279 | } 280 | while (fgets(line, sizeof(line), f) != NULL) { 281 | if (line[0] != '#' && line[0] != '\n') { 282 | l = line; 283 | while (*l == ' ') { 284 | l++; 285 | } 286 | if (sscanf(l, "proposer %d %s", &id, addr) == 2 && id == cl->prop_id) { 287 | str_to_mac(addr, cl->prop_addr); 288 | return 0; 289 | } 290 | } 291 | } 292 | return 1; 293 | } 294 | -------------------------------------------------------------------------------- /evpaxos/evacceptor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "acceptor.h" 29 | #include "evpaxos.h" 30 | #include "message.h" 31 | #include "peers.h" 32 | #include 33 | #include 34 | 35 | struct evacceptor 36 | { 37 | struct peers* peers; 38 | struct acceptor* state; 39 | struct timer_list stats_ev; 40 | struct timeval stats_interval; 41 | }; 42 | 43 | static inline void 44 | send_acceptor_paxos_message(struct net_device* dev, struct peer* p, void* arg) 45 | { 46 | send_paxos_message(dev, get_addr(p), arg); 47 | } 48 | 49 | /* 50 | Received a prepare request (phase 1a). 51 | */ 52 | static void 53 | evacceptor_handle_prepare(paxos_message* msg, void* arg, eth_address* src) 54 | { 55 | paxos_message out; 56 | paxos_prepare* prepare = &msg->u.prepare; 57 | struct evacceptor* a = (struct evacceptor*)arg; 58 | add_or_update_client(src, a->peers); 59 | paxos_log_debug("Received PREPARE"); 60 | if (acceptor_receive_prepare(a->state, prepare, &out) != 0) { 61 | send_paxos_message(get_dev(a->peers), src, &out); 62 | paxos_message_destroy(&out); 63 | } 64 | } 65 | 66 | /* 67 | Received a accept request (phase 2a). 68 | */ 69 | static void 70 | evacceptor_handle_accept(paxos_message* msg, void* arg, eth_address* src) 71 | { 72 | paxos_message out, out2; 73 | paxos_accept* accept = &msg->u.accept; 74 | struct evacceptor* a = (struct evacceptor*)arg; 75 | paxos_log_debug("Received ACCEPT REQUEST"); 76 | paxos_prepare prepare = 77 | (paxos_prepare){ .iid = accept->promise_iid, .ballot = accept->ballot }; 78 | uint32_t promise_iid = 0; 79 | if (acceptor_receive_accept(a->state, accept, &out) != 0) { 80 | 81 | if (acceptor_receive_prepare(a->state, &prepare, &out2) != 0) { 82 | promise_iid = out2.u.promise.iid; 83 | if (out2.u.promise.ballot > accept->ballot || 84 | out2.u.promise.value_ballot > 0) { 85 | out.u.accepted.promise_iid = 0; 86 | send_paxos_message(get_dev(a->peers), src, &out2); 87 | paxos_message_destroy(&out2); 88 | promise_iid = 0; 89 | } 90 | } 91 | 92 | if (out.type == PAXOS_ACCEPTED) { 93 | out.u.accepted.promise_iid = promise_iid; 94 | peers_foreach_client(a->peers, send_acceptor_paxos_message, &out); 95 | paxos_log_debug("Sent ACCEPTED to all proposers and learners"); 96 | } else if (out.type == PAXOS_PREEMPTED) { 97 | send_paxos_message(get_dev(a->peers), src, &out); 98 | paxos_log_debug("Sent PREEMPTED to the proposer "); 99 | } 100 | 101 | paxos_message_destroy(&out); 102 | } 103 | } 104 | 105 | static void 106 | evacceptor_handle_repeat(paxos_message* msg, void* arg, eth_address* src) 107 | { 108 | iid_t iid; 109 | paxos_accepted accepted; 110 | paxos_repeat* repeat = &msg->u.repeat; 111 | struct evacceptor* a = (struct evacceptor*)arg; 112 | paxos_log_debug("Handle repeat for iids %d-%d", repeat->from, repeat->to); 113 | for (iid = repeat->from; iid <= repeat->to; ++iid) { 114 | if (acceptor_receive_repeat(a->state, iid, &accepted)) { 115 | paxos_log_debug("sent a repeated PAXOS_ACCEPTED %d to learner", iid); 116 | send_paxos_accepted(get_dev(a->peers), src, &accepted); 117 | paxos_accepted_destroy(&accepted); 118 | } 119 | } 120 | } 121 | 122 | static void 123 | evacceptor_handle_trim(paxos_message* msg, void* arg, eth_address* src) 124 | { 125 | paxos_trim* trim = &msg->u.trim; 126 | struct evacceptor* a = (struct evacceptor*)arg; 127 | acceptor_receive_trim(a->state, trim); 128 | } 129 | 130 | static void 131 | evacceptor_handle_hi(paxos_message* msg, void* arg, eth_address* src) 132 | { 133 | 134 | struct evacceptor* a = (struct evacceptor*)arg; 135 | if (add_or_update_client(src, a->peers)) { 136 | paxos_log_debug("Received PAXOS_LEARNER_HI. Sending OK"); 137 | send_paxos_acceptor_ok(get_dev(a->peers), src); 138 | } 139 | } 140 | 141 | static void 142 | evacceptor_handle_del(paxos_message* msg, void* arg, eth_address* src) 143 | { 144 | paxos_log_debug("Received PAXOS_LEARNER_DEL."); 145 | struct evacceptor* a = (struct evacceptor*)arg; 146 | peers_delete_learner(a->peers, src); 147 | } 148 | 149 | static void 150 | send_acceptor_state(unsigned long arg) 151 | { 152 | struct evacceptor* a = (struct evacceptor*)arg; 153 | paxos_message msg = { .type = PAXOS_ACCEPTOR_STATE }; 154 | acceptor_set_current_state(a->state, &msg.u.state); 155 | peers_foreach_client(a->peers, send_acceptor_paxos_message, &msg); 156 | mod_timer(&a->stats_ev, jiffies + timeval_to_jiffies(&a->stats_interval)); 157 | } 158 | 159 | struct evacceptor* 160 | evacceptor_init_internal(int id, struct evpaxos_config* c, struct peers* p) 161 | { 162 | struct evacceptor* acceptor; 163 | 164 | acceptor = pmalloc(sizeof(struct evacceptor)); 165 | if (acceptor == NULL) { 166 | return NULL; 167 | } 168 | memset(acceptor, 0, sizeof(struct evacceptor)); 169 | acceptor->state = acceptor_new(id); 170 | acceptor->peers = p; 171 | 172 | peers_add_subscription(p, PAXOS_PREPARE, evacceptor_handle_prepare, acceptor); 173 | peers_add_subscription(p, PAXOS_ACCEPT, evacceptor_handle_accept, acceptor); 174 | peers_add_subscription(p, PAXOS_REPEAT, evacceptor_handle_repeat, acceptor); 175 | peers_add_subscription(p, PAXOS_TRIM, evacceptor_handle_trim, acceptor); 176 | peers_add_subscription(p, PAXOS_LEARNER_HI, evacceptor_handle_hi, acceptor); 177 | peers_add_subscription(p, PAXOS_LEARNER_DEL, evacceptor_handle_del, acceptor); 178 | 179 | setup_timer(&acceptor->stats_ev, send_acceptor_state, 180 | (unsigned long)acceptor); 181 | acceptor->stats_interval = (struct timeval){ 1, 0 }; 182 | mod_timer(&acceptor->stats_ev, 183 | jiffies + timeval_to_jiffies(&acceptor->stats_interval)); 184 | 185 | return acceptor; 186 | } 187 | 188 | struct evacceptor* 189 | evacceptor_init(int id, char* if_name, char* path) 190 | { 191 | struct evpaxos_config* config = evpaxos_config_read(path); 192 | if (config == NULL) 193 | return NULL; 194 | 195 | int acceptor_count = evpaxos_acceptor_count(config); 196 | if (id < 0 || id >= acceptor_count) { 197 | paxos_log_error("Invalid acceptor id: %d, should be between 0 and %d", id, 198 | (acceptor_count - 1)); 199 | evpaxos_config_free(config); 200 | return NULL; 201 | } 202 | 203 | struct peers* peers = peers_new(config, id, if_name); 204 | if (peers == NULL) 205 | return NULL; 206 | printall(peers, "Acceptor"); 207 | struct evacceptor* acceptor = evacceptor_init_internal(id, config, peers); 208 | peers_subscribe(peers); 209 | evpaxos_config_free(config); 210 | return acceptor; 211 | } 212 | 213 | void 214 | evacceptor_free_internal(struct evacceptor* a) 215 | { 216 | acceptor_free(a->state); 217 | del_timer(&a->stats_ev); 218 | pfree(a); 219 | } 220 | 221 | void 222 | evacceptor_free(struct evacceptor* a) 223 | { 224 | printall(a->peers, "ACCEPTOR"); 225 | peers_free(a->peers); 226 | evacceptor_free_internal(a); 227 | } 228 | -------------------------------------------------------------------------------- /evpaxos/evproposer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "eth.h" 29 | #include "evpaxos.h" 30 | #include "message.h" 31 | #include "peers.h" 32 | #include "proposer.h" 33 | #include 34 | 35 | struct evproposer 36 | { 37 | int id; 38 | int preexec_window; 39 | struct proposer* state; 40 | struct peers* peers; 41 | struct timer_list stats_ev; 42 | struct timeval stats_interval; 43 | }; 44 | 45 | static inline void 46 | peer_send_prepare(struct net_device* dev, struct peer* p, void* arg) 47 | { 48 | send_paxos_prepare(dev, get_addr(p), arg); 49 | } 50 | 51 | static inline void 52 | peer_send_accept(struct net_device* dev, struct peer* p, void* arg) 53 | { 54 | send_paxos_accept(dev, get_addr(p), arg); 55 | } 56 | 57 | static void 58 | proposer_preexecute(struct evproposer* p) 59 | { 60 | int i; 61 | paxos_prepare pr; 62 | int count = p->preexec_window - proposer_prepared_count(p->state); 63 | 64 | if (count <= 0) 65 | return; 66 | for (i = 0; i < count; i++) { 67 | proposer_prepare(p->state, &pr); 68 | peers_foreach_acceptor(p->peers, peer_send_prepare, &pr); 69 | } 70 | paxos_log_debug("Proposer: Opened %d new instances", count); 71 | } 72 | 73 | static void 74 | try_accept(struct evproposer* p) 75 | { 76 | paxos_accept accept; 77 | paxos_prepare pr; 78 | while (proposer_accept(p->state, &accept)) { 79 | int count = p->preexec_window - proposer_prepared_count(p->state); 80 | pr.iid = 0; 81 | pr.ballot = accept.ballot; 82 | if (count > 0) 83 | proposer_prepare(p->state, &pr); 84 | accept.promise_iid = pr.iid; 85 | peers_foreach_acceptor(p->peers, peer_send_accept, &accept); 86 | } 87 | // proposer_preexecute(p); 88 | } 89 | 90 | static void 91 | evproposer_handle_promise(paxos_message* msg, void* arg, eth_address* src) 92 | { 93 | struct evproposer* proposer = arg; 94 | paxos_prepare prepare; 95 | paxos_promise* pro = &msg->u.promise; 96 | int preempted = proposer_receive_promise(proposer->state, pro, &prepare); 97 | if (preempted) 98 | peers_foreach_acceptor(proposer->peers, peer_send_prepare, &prepare); 99 | try_accept(proposer); 100 | } 101 | 102 | static void 103 | evproposer_handle_accepted(paxos_message* msg, void* arg, eth_address* src) 104 | { 105 | struct evproposer* proposer = arg; 106 | paxos_message prom; 107 | paxos_prepare prep; 108 | paxos_accepted* acc = &msg->u.accepted; 109 | int preempted; 110 | 111 | if (acc->promise_iid) { 112 | prom.type = PAXOS_PROMISE; 113 | prom.u.promise = 114 | (paxos_promise){ .aid = acc->aid, 115 | .iid = acc->promise_iid, 116 | .ballot = acc->ballot, 117 | .value_ballot = 0, 118 | .value = (paxos_value){ .paxos_value_val = NULL, 119 | .paxos_value_len = 0 } }; 120 | preempted = 121 | proposer_receive_promise(proposer->state, &prom.u.promise, &prep); 122 | if (preempted) 123 | paxos_log_error("Proposer: piggybacked prepare has been preempted!"); 124 | // peers_foreach_acceptor(proposer->peers, peer_send_prepare, &prep); 125 | } 126 | if (proposer_receive_accepted(proposer->state, acc)) 127 | try_accept(proposer); 128 | } 129 | 130 | static void 131 | evproposer_handle_preempted(paxos_message* msg, void* arg, eth_address* src) 132 | { 133 | struct evproposer* proposer = arg; 134 | paxos_prepare prepare; 135 | int preempted = 136 | proposer_receive_preempted(proposer->state, &msg->u.preempted, &prepare); 137 | if (preempted) { 138 | peers_foreach_acceptor(proposer->peers, peer_send_prepare, &prepare); 139 | try_accept(proposer); 140 | } 141 | } 142 | 143 | static void 144 | evproposer_handle_client_value(paxos_message* msg, void* arg, eth_address* src) 145 | { 146 | struct evproposer* proposer = arg; 147 | struct paxos_client_value* v = &msg->u.client_value; 148 | 149 | proposer_propose(proposer->state, v->value.paxos_value_val, 150 | v->value.paxos_value_len); 151 | paxos_log_debug("Proposer: received a CLIENT VALUE"); 152 | try_accept(proposer); 153 | } 154 | 155 | static void 156 | evproposer_handle_acceptor_state(paxos_message* msg, void* arg, 157 | eth_address* src) 158 | { 159 | paxos_log_debug("Proposer: received a ACCEPTOR STATE"); 160 | struct evproposer* proposer = arg; 161 | struct paxos_acceptor_state* acc_state = &msg->u.state; 162 | proposer_receive_acceptor_state(proposer->state, acc_state); 163 | } 164 | 165 | void 166 | evproposer_preexec_once(struct evproposer* arg) 167 | { 168 | if (arg) 169 | proposer_preexecute(arg); 170 | } 171 | 172 | static void 173 | evproposer_check_timeouts(unsigned long arg) 174 | { 175 | 176 | struct evproposer* p = (struct evproposer*)arg; 177 | struct timeout_iterator* iter = proposer_timeout_iterator(p->state); 178 | 179 | paxos_prepare pr; 180 | while (timeout_iterator_prepare(iter, &pr)) { 181 | paxos_log_debug("Proposer: Instance %d timed out in phase 1.", pr.iid); 182 | peers_foreach_acceptor(p->peers, peer_send_prepare, &pr); 183 | } 184 | 185 | paxos_accept ar; 186 | while (timeout_iterator_accept(iter, &ar)) { 187 | paxos_log_debug("Proposer: Instance %d timed out in phase 2.", ar.iid); 188 | peers_foreach_acceptor(p->peers, peer_send_accept, &ar); 189 | } 190 | 191 | timeout_iterator_free(iter); 192 | mod_timer(&p->stats_ev, jiffies + timeval_to_jiffies(&p->stats_interval)); 193 | } 194 | 195 | struct evproposer* 196 | evproposer_init_internal(int id, struct evpaxos_config* c, struct peers* peers) 197 | { 198 | 199 | struct evproposer* proposer; 200 | int acceptor_count = evpaxos_acceptor_count(c); 201 | 202 | proposer = pmalloc(sizeof(struct evproposer)); 203 | if (proposer == NULL) 204 | return NULL; 205 | memset(proposer, 0, sizeof(struct evproposer)); 206 | 207 | proposer->id = id; 208 | proposer->preexec_window = paxos_config.proposer_preexec_window; 209 | proposer->state = proposer_new(proposer->id, acceptor_count); 210 | proposer->peers = peers; 211 | 212 | peers_add_subscription(peers, PAXOS_PROMISE, evproposer_handle_promise, 213 | proposer); 214 | peers_add_subscription(peers, PAXOS_ACCEPTED, evproposer_handle_accepted, 215 | proposer); 216 | peers_add_subscription(peers, PAXOS_PREEMPTED, evproposer_handle_preempted, 217 | proposer); 218 | peers_add_subscription(peers, PAXOS_CLIENT_VALUE, 219 | evproposer_handle_client_value, proposer); 220 | peers_add_subscription(peers, PAXOS_ACCEPTOR_STATE, 221 | evproposer_handle_acceptor_state, proposer); 222 | 223 | setup_timer(&proposer->stats_ev, evproposer_check_timeouts, 224 | (unsigned long)proposer); 225 | proposer->stats_interval = 226 | (struct timeval){ paxos_config.proposer_timeout, 0 }; 227 | mod_timer(&proposer->stats_ev, 228 | jiffies + timeval_to_jiffies(&proposer->stats_interval)); 229 | 230 | return proposer; 231 | } 232 | 233 | struct evproposer* 234 | evproposer_init(int id, char* if_name, char* path) 235 | { 236 | struct evpaxos_config* config = evpaxos_config_read(path); 237 | if (config == NULL) 238 | return NULL; 239 | 240 | if (id < 0 || id >= evpaxos_proposer_count(config)) { 241 | paxos_log_error("Invalid proposer id: %d", id); 242 | return NULL; 243 | } 244 | 245 | struct peers* peers = peers_new(config, id, if_name); 246 | if (peers == NULL) 247 | return NULL; 248 | 249 | add_acceptors_from_config(peers, config); 250 | printall(peers, "Proposer"); 251 | struct evproposer* p = evproposer_init_internal(id, config, peers); 252 | peers_subscribe(peers); 253 | evproposer_preexec_once(p); 254 | evpaxos_config_free(config); 255 | return p; 256 | } 257 | 258 | void 259 | evproposer_free_internal(struct evproposer* p) 260 | { 261 | del_timer(&p->stats_ev); 262 | proposer_free(p->state); 263 | pfree(p); 264 | } 265 | 266 | void 267 | evproposer_free(struct evproposer* p) 268 | { 269 | printall(p->peers, "PROPOSER"); 270 | peers_free(p->peers); 271 | evproposer_free_internal(p); 272 | } 273 | 274 | void 275 | evproposer_set_instance_id(struct evproposer* p, unsigned iid) 276 | { 277 | proposer_set_instance_id(p->state, iid); 278 | } 279 | -------------------------------------------------------------------------------- /evpaxos/peers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "peers.h" 29 | #include "message.h" 30 | #include 31 | 32 | #include "eth.h" 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | struct peer 40 | { 41 | int id; 42 | eth_address addr[ETH_ALEN]; 43 | struct peers* peers; 44 | }; 45 | 46 | struct peers 47 | { 48 | int peers_count, clients_count; 49 | struct peer** peers; /* peers we connected to */ 50 | struct peer** clients; /* peers we accepted connections from */ 51 | struct net_device* dev; 52 | }; 53 | 54 | int* peers_received_ok = NULL; 55 | int ok_received; 56 | 57 | static struct peer* make_peer(struct peers* p, int id, eth_address* in); 58 | static void free_peer(struct peer* p); 59 | static void free_all_peers(struct peer** p, int count); 60 | 61 | static void 62 | check_id(struct peers* p, struct evpaxos_config* config, int id) 63 | { 64 | paxos_log_debug("check Id %d\n", id); 65 | if (id < 0) 66 | return; 67 | 68 | eth_address* ad1 = evpaxos_acceptor_address(config, id); 69 | eth_address* ad2 = evpaxos_proposer_address(config, id); 70 | if (ad1 != NULL) { 71 | paxos_log_debug( 72 | "Comparing " 73 | "\n%02x:%02x:%02x:%02x:%02x:%02x\n%02x:%02x:%02x:%02x:%02x:%02x\n", 74 | p->dev->dev_addr[0], p->dev->dev_addr[1], p->dev->dev_addr[2], 75 | p->dev->dev_addr[3], p->dev->dev_addr[4], p->dev->dev_addr[5], ad1[0], 76 | ad1[1], ad1[2], ad1[3], ad1[4], ad1[5]); 77 | if (memcmp(p->dev->dev_addr, ad1, ETH_ALEN) == 0) 78 | return; 79 | } 80 | 81 | if (ad2 != NULL) { 82 | paxos_log_debug( 83 | "Comparing " 84 | "\n%02x:%02x:%02x:%02x:%02x:%02x\n%02x:%02x:%02x:%02x:%02x:%02x\n", 85 | p->dev->dev_addr[0], p->dev->dev_addr[1], p->dev->dev_addr[2], 86 | p->dev->dev_addr[3], p->dev->dev_addr[4], p->dev->dev_addr[5], ad2[0], 87 | ad2[1], ad2[2], ad2[3], ad2[4], ad2[5]); 88 | if (memcmp(p->dev->dev_addr, ad2, ETH_ALEN) == 0) 89 | return; 90 | } 91 | 92 | paxos_log_error("Warning: address %02x:%02x:%02x:%02x:%02x:%02x is not " 93 | "present in the config file", 94 | p->dev->dev_addr[0], p->dev->dev_addr[1], p->dev->dev_addr[2], 95 | p->dev->dev_addr[3], p->dev->dev_addr[4], 96 | p->dev->dev_addr[5]); 97 | } 98 | 99 | struct peers* 100 | peers_new(struct evpaxos_config* config, int id, char* if_name) 101 | { 102 | struct peers* p = pmalloc(sizeof(struct peers)); 103 | p->peers_count = 0; 104 | p->clients_count = 0; 105 | p->peers = NULL; 106 | p->clients = NULL; 107 | 108 | p->dev = eth_init(if_name); 109 | if (p->dev == NULL) { 110 | printk(KERN_ERR "Interface not found: %s\n", if_name); 111 | pfree(p); 112 | return NULL; 113 | } 114 | check_id(p, config, id); 115 | return p; 116 | } 117 | 118 | void 119 | peers_free(struct peers* p) 120 | { 121 | eth_destroy(p->dev); 122 | free_all_peers(p->peers, p->peers_count); 123 | free_all_peers(p->clients, p->clients_count); 124 | pfree(p); 125 | } 126 | 127 | int 128 | peers_count(struct peers* p) 129 | { 130 | return p->peers_count; 131 | } 132 | 133 | eth_address* 134 | get_addr(struct peer* p) 135 | { 136 | return p->addr; 137 | } 138 | 139 | void 140 | peers_foreach_acceptor(struct peers* p, peer_iter_cb cb, void* arg) 141 | { 142 | int i; 143 | for (i = 0; i < p->peers_count; ++i) { 144 | cb(p->dev, p->peers[i], arg); 145 | } 146 | } 147 | 148 | void 149 | peers_foreach_client(struct peers* p, peer_iter_cb cb, void* arg) 150 | { 151 | int i; 152 | for (i = 0; i < p->clients_count; ++i) 153 | cb(p->dev, p->clients[i], arg); 154 | } 155 | 156 | struct peer* 157 | peers_get_acceptor(struct peers* p, int id) 158 | { 159 | int i; 160 | for (i = 0; p->peers_count; ++i) 161 | if (p->peers[i]->id == id) 162 | return p->peers[i]; 163 | return NULL; 164 | } 165 | 166 | // add all acceptors in the peers 167 | void 168 | add_acceptors_from_config(struct peers* p, struct evpaxos_config* conf) 169 | { 170 | eth_address* addr; 171 | int n = evpaxos_acceptor_count(conf); 172 | p->peers = prealloc(p->peers, sizeof(struct peer*) * n); 173 | 174 | for (int i = 0; i < n; i++) { 175 | addr = evpaxos_acceptor_address(conf, i); 176 | if (addr) 177 | p->peers[p->peers_count++] = make_peer(p, i, addr); 178 | } 179 | peers_received_ok = pmalloc(sizeof(int) * p->peers_count); 180 | memset(peers_received_ok, 0, sizeof(int) * p->peers_count); 181 | } 182 | 183 | void 184 | printall(struct peers* p, char* name) 185 | { 186 | paxos_log_info("%s", name); 187 | paxos_log_info("\tME address %02x:%02x:%02x:%02x:%02x:%02x", 188 | p->dev->dev_addr[0], p->dev->dev_addr[1], p->dev->dev_addr[2], 189 | p->dev->dev_addr[3], p->dev->dev_addr[4], p->dev->dev_addr[5]); 190 | paxos_log_info("PEERS we connect to"); 191 | int i; 192 | for (i = 0; i < p->peers_count; i++) { 193 | paxos_log_info("\tid=%d address " 194 | "%02x:%02x:%02x:%02x:%02x:%02x", 195 | p->peers[i]->id, p->peers[i]->addr[0], p->peers[i]->addr[1], 196 | p->peers[i]->addr[2], p->peers[i]->addr[3], 197 | p->peers[i]->addr[4], p->peers[i]->addr[5]); 198 | } 199 | 200 | paxos_log_info("CLIENTS we receive connections "); 201 | paxos_log_info("(will be updated as message are received"); 202 | 203 | for (i = 0; i < p->clients_count; i++) { 204 | paxos_log_info( 205 | "\tid=%d address %02x:%02x:%02x:%02x:%02x:%02x", p->clients[i]->id, 206 | p->clients[i]->addr[0], p->clients[i]->addr[1], p->clients[i]->addr[2], 207 | p->clients[i]->addr[3], p->clients[i]->addr[4], p->clients[i]->addr[5]); 208 | } 209 | paxos_log_info(""); 210 | } 211 | 212 | int 213 | peer_get_id(struct peer* p) 214 | { 215 | return p->id; 216 | } 217 | 218 | // 0 if known, 1 if new 219 | int 220 | add_or_update_client(eth_address* addr, struct peers* p) 221 | { 222 | int i; 223 | for (i = 0; i < p->clients_count; ++i) { 224 | if (memcmp(addr, p->clients[i]->addr, ETH_ALEN) == 0) { 225 | return 0; 226 | } 227 | } 228 | 229 | paxos_log_info("Added a new client, now %d clients", p->clients_count + 1); 230 | p->clients = 231 | prealloc(p->clients, sizeof(struct peer) * (p->clients_count + 1)); 232 | p->clients[p->clients_count] = make_peer(p, p->clients_count, addr); 233 | p->clients_count++; 234 | return 1; 235 | } 236 | 237 | void 238 | peer_send_del(struct net_device* dev, struct peer* p, void* arg) 239 | { 240 | send_paxos_learner_del(dev, get_addr(p)); 241 | } 242 | 243 | struct net_device* 244 | get_dev(struct peers* p) 245 | { 246 | return p->dev; 247 | } 248 | 249 | int 250 | peers_missing_ok(struct peers* p) 251 | { 252 | return (ok_received != p->peers_count); 253 | } 254 | 255 | void 256 | peers_update_ok(struct peers* p, eth_address* addr) 257 | { 258 | int i; 259 | for (i = 0; i < p->peers_count; ++i) { 260 | if (memcmp(addr, p->peers[i]->addr, ETH_ALEN) == 0 && 261 | peers_received_ok[p->peers[i]->id] == 0) { 262 | paxos_log_debug("peers_received_ok[%d] = 1", p->peers[i]->id); 263 | peers_received_ok[p->peers[i]->id] = 1; 264 | ok_received++; 265 | break; 266 | } 267 | } 268 | } 269 | 270 | void 271 | peers_delete_learner(struct peers* p, eth_address* addr) 272 | { 273 | int i, j; 274 | for (i = 0; i < p->clients_count; ++i) { 275 | if (memcmp(addr, p->clients[i]->addr, ETH_ALEN) == 0) { 276 | pfree(p->clients[i]); 277 | for (j = i; j < p->clients_count - 1; ++j) { 278 | p->clients[j] = p->clients[j + 1]; 279 | p->clients[j]->id = j; 280 | } 281 | p->clients_count--; 282 | p->clients = 283 | prealloc(p->clients, sizeof(struct peer*) * (p->clients_count)); 284 | break; 285 | } 286 | } 287 | } 288 | 289 | void 290 | peers_subscribe(struct peers* p) 291 | { 292 | eth_listen(p->dev); 293 | } 294 | 295 | void 296 | peers_add_subscription(struct peers* p, paxos_message_type type, peer_cb cb, 297 | void* arg) 298 | { 299 | eth_subscribe(p->dev, (uint16_t)type, cb, arg); 300 | } 301 | 302 | static struct peer* 303 | make_peer(struct peers* peers, int id, eth_address* addr) 304 | { 305 | struct peer* p = pmalloc(sizeof(struct peer)); 306 | p->id = id; 307 | memcpy(p->addr, addr, ETH_ALEN); 308 | p->peers = peers; 309 | return p; 310 | } 311 | 312 | static void 313 | free_all_peers(struct peer** p, int count) 314 | { 315 | int i; 316 | for (i = 0; i < count; i++) 317 | free_peer(p[i]); 318 | if (count > 0) 319 | pfree(p); 320 | } 321 | 322 | static void 323 | free_peer(struct peer* p) 324 | { 325 | pfree(p); 326 | } 327 | -------------------------------------------------------------------------------- /paxos/learner.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2013-2014, University of Lugano 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the copyright holders nor the names of it 13 | * contributors may be used to endorse or promote products derived from 14 | * this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | #include "learner.h" 29 | #include "linux/slab.h" 30 | #include "uthash.h" 31 | 32 | #ifndef HASH_FIND_IID 33 | #define HASH_FIND_IID(head, findint, out) \ 34 | HASH_FIND(hh, head, findint, sizeof(iid_t), out) 35 | #endif 36 | 37 | #ifndef HASH_ADD_IID 38 | #define HASH_ADD_IID(head, intfield, add) \ 39 | HASH_ADD(hh, head, intfield, sizeof(iid_t), add) 40 | #endif 41 | 42 | struct instance 43 | { 44 | iid_t iid; 45 | ballot_t last_update_ballot; 46 | paxos_accepted** acks; 47 | paxos_accepted* final_value; 48 | UT_hash_handle hh; 49 | }; 50 | 51 | struct learner 52 | { 53 | int acceptors; 54 | int late_start; 55 | iid_t current_iid; 56 | iid_t highest_iid_closed; 57 | struct instance* instances; 58 | }; 59 | 60 | static struct instance* learner_get_instance(struct learner* l, iid_t iid); 61 | static struct instance* learner_get_current_instance(struct learner* l); 62 | static struct instance* learner_get_instance_or_create(struct learner* l, 63 | iid_t iid); 64 | static void learner_delete_instance(struct learner* l, struct instance* inst); 65 | static struct instance* instance_new(int acceptors); 66 | static void instance_free(struct instance* i, int acceptors); 67 | static void instance_update(struct instance* i, paxos_accepted* ack, 68 | int acceptors); 69 | static int instance_has_quorum(struct instance* i, int acceptors); 70 | static void instance_add_accept(struct instance* i, paxos_accepted* ack); 71 | static paxos_accepted* paxos_accepted_dup(paxos_accepted* ack); 72 | static void paxos_value_copy(paxos_value* dst, paxos_value* src); 73 | 74 | struct learner* 75 | learner_new(int acceptors) 76 | { 77 | struct learner* l; 78 | l = pmalloc(sizeof(struct learner)); 79 | if (l) { 80 | l->acceptors = acceptors; 81 | l->current_iid = 1; 82 | l->highest_iid_closed = 1; 83 | if (paxos_config.learner_catch_up) { 84 | LOG_INFO("Catch up on"); 85 | } else { 86 | LOG_INFO("Catch up off"); 87 | } 88 | l->late_start = !paxos_config.learner_catch_up; 89 | l->instances = NULL; 90 | } 91 | return l; 92 | } 93 | 94 | void 95 | learner_free(struct learner* l) 96 | { 97 | struct instance *inst, *tmp; 98 | 99 | HASH_ITER(hh, l->instances, inst, tmp) 100 | { 101 | HASH_DEL(l->instances, inst); 102 | instance_free(inst, l->acceptors); 103 | } 104 | pfree(l); 105 | } 106 | 107 | void 108 | learner_set_instance_id(struct learner* l, iid_t iid) 109 | { 110 | l->current_iid = iid + 1; 111 | l->highest_iid_closed = iid; 112 | } 113 | 114 | void 115 | learner_receive_accepted(struct learner* l, paxos_accepted* ack) 116 | { 117 | if (l->late_start) { 118 | l->late_start = 0; 119 | l->current_iid = ack->iid; 120 | } 121 | 122 | if (ack->iid < l->current_iid) { 123 | paxos_log_debug( 124 | "Learner: Dropped paxos_accepted for iid %u. Already delivered.", 125 | ack->iid); 126 | return; 127 | } 128 | 129 | struct instance* inst; 130 | inst = learner_get_instance_or_create(l, ack->iid); 131 | instance_update(inst, ack, l->acceptors); 132 | 133 | if (instance_has_quorum(inst, l->acceptors) && 134 | (inst->iid > l->highest_iid_closed)) { 135 | l->highest_iid_closed = inst->iid; 136 | } 137 | } 138 | 139 | int 140 | learner_deliver_next(struct learner* l, paxos_accepted* out) 141 | { 142 | struct instance* inst = learner_get_current_instance(l); 143 | 144 | if (inst == NULL || !instance_has_quorum(inst, l->acceptors)) { 145 | return 0; 146 | } 147 | 148 | memcpy(out, inst->final_value, sizeof(paxos_accepted)); 149 | paxos_value_copy(&out->value, &inst->final_value->value); 150 | paxos_log_debug("Learner: Deleted instance %u.", inst->iid); 151 | learner_delete_instance(l, inst); 152 | l->current_iid++; 153 | return 1; 154 | } 155 | 156 | int 157 | learner_has_holes(struct learner* l, iid_t* from, iid_t* to) 158 | { 159 | if (l->highest_iid_closed > l->current_iid) { 160 | *from = l->current_iid; 161 | *to = l->highest_iid_closed; 162 | return 1; 163 | } 164 | return 0; 165 | } 166 | 167 | static struct instance* 168 | learner_get_instance(struct learner* l, iid_t iids) 169 | { 170 | struct instance* h = NULL; 171 | HASH_FIND_IID(l->instances, &iids, h); 172 | return h; 173 | } 174 | 175 | static struct instance* 176 | learner_get_current_instance(struct learner* l) 177 | { 178 | return learner_get_instance(l, l->current_iid); 179 | } 180 | 181 | static struct instance* 182 | learner_get_instance_or_create(struct learner* l, iid_t iids) 183 | { 184 | struct instance* inst = learner_get_instance(l, iids); 185 | if (inst == NULL) { 186 | inst = instance_new(l->acceptors); 187 | inst->iid = iids; 188 | HASH_ADD_IID(l->instances, iid, inst); 189 | } 190 | return inst; 191 | } 192 | 193 | static void 194 | learner_delete_instance(struct learner* l, struct instance* inst) 195 | { 196 | HASH_DEL(l->instances, inst); 197 | instance_free(inst, l->acceptors); 198 | } 199 | 200 | static struct instance* 201 | instance_new(int acceptors) 202 | { 203 | int i; 204 | struct instance* inst; 205 | inst = pmalloc(sizeof(struct instance)); 206 | if (inst) { 207 | memset(inst, 0, sizeof(struct instance)); 208 | inst->acks = pmalloc(sizeof(paxos_accepted*) * acceptors); 209 | if (inst->acks) { 210 | for (i = 0; i < acceptors; ++i) 211 | inst->acks[i] = NULL; 212 | } 213 | } 214 | return inst; 215 | } 216 | 217 | static void 218 | instance_free(struct instance* inst, int acceptors) 219 | { 220 | int i; 221 | for (i = 0; i < acceptors; i++) 222 | if (inst->acks[i] != NULL) 223 | paxos_accepted_free(inst->acks[i]); 224 | pfree(inst->acks); 225 | pfree(inst); 226 | } 227 | 228 | static void 229 | instance_update(struct instance* inst, paxos_accepted* accepted, int acceptors) 230 | { 231 | if (inst->iid == 0) { 232 | inst->iid = accepted->iid; 233 | inst->last_update_ballot = accepted->ballot; 234 | } 235 | 236 | if (instance_has_quorum(inst, acceptors)) { 237 | paxos_log_debug("Learner: Dropped paxos_accepted iid %u. Already closed.", 238 | accepted->iid); 239 | return; 240 | } 241 | 242 | paxos_accepted* prev_accepted = inst->acks[accepted->aid]; 243 | if (prev_accepted != NULL && prev_accepted->ballot >= accepted->ballot) { 244 | paxos_log_debug("Learner: Dropped paxos_accepted for iid %u, previous " 245 | "ballot is newer or equal.", 246 | accepted->iid); 247 | return; 248 | } 249 | 250 | instance_add_accept(inst, accepted); 251 | } 252 | 253 | /* 254 | Checks if a given instance is closed, that is if a quorum of acceptor 255 | accepted the same value ballot pair. 256 | Returns 1 if the instance is closed, 0 otherwise. 257 | */ 258 | static int 259 | instance_has_quorum(struct instance* inst, int acceptors) 260 | { 261 | paxos_accepted* curr_ack; 262 | int i, a_valid_index = -1, count = 0; 263 | 264 | if (inst->final_value != NULL) 265 | return 1; 266 | 267 | for (i = 0; i < acceptors; i++) { 268 | curr_ack = inst->acks[i]; 269 | 270 | // Skip over missing acceptor acks 271 | if (curr_ack == NULL) 272 | continue; 273 | 274 | // Count the ones "agreeing" with the last added 275 | if (curr_ack->ballot == inst->last_update_ballot) { 276 | count++; 277 | a_valid_index = i; 278 | } 279 | } 280 | 281 | if (count >= paxos_quorum(acceptors)) { 282 | paxos_log_debug("Learner: Reached quorum, iid: %u is closed!", inst->iid); 283 | inst->final_value = inst->acks[a_valid_index]; 284 | return 1; 285 | } 286 | 287 | return 0; 288 | } 289 | 290 | /* 291 | Adds the given paxos_accepted to the given instance, 292 | replacing the previous paxos_accepted, if any. 293 | */ 294 | static void 295 | instance_add_accept(struct instance* inst, paxos_accepted* accepted) 296 | { 297 | int acceptor_id = accepted->aid; 298 | if (inst->acks[acceptor_id] != NULL) 299 | paxos_accepted_free(inst->acks[acceptor_id]); 300 | inst->acks[acceptor_id] = paxos_accepted_dup(accepted); 301 | inst->last_update_ballot = accepted->ballot; 302 | } 303 | 304 | /* 305 | Returns a copy of it's argument. 306 | */ 307 | static paxos_accepted* 308 | paxos_accepted_dup(paxos_accepted* ack) 309 | { 310 | paxos_accepted* copy; 311 | copy = pmalloc(sizeof(paxos_accepted)); 312 | if (copy) { 313 | memcpy(copy, ack, sizeof(paxos_accepted)); 314 | paxos_value_copy(©->value, &ack->value); 315 | } 316 | return copy; 317 | } 318 | 319 | static void 320 | paxos_value_copy(paxos_value* dst, paxos_value* src) 321 | { 322 | int len = src->paxos_value_len; 323 | dst->paxos_value_len = len; 324 | if (src->paxos_value_val != NULL) { 325 | dst->paxos_value_val = pmalloc(len); 326 | if (dst->paxos_value_val) 327 | memcpy(dst->paxos_value_val, src->paxos_value_val, len); 328 | } 329 | } 330 | --------------------------------------------------------------------------------