Add implementation of class-of-service
authorNeutron Soutmun <neo.neutron@gmail.com>
Thu, 29 Jul 2010 16:34:53 +0000 (23:34 +0700)
committerNeutron Soutmun <neo.neutron@gmail.com>
Thu, 29 Jul 2010 16:34:53 +0000 (23:34 +0700)
  * Add new implementation of class-of-service which respect to the RADIUS
    Attribute "WISPr-Billing-Class-Of-Service"
  * Remove the concept of vip users and use the class-of-service concept which
    more flexibility instead.
  * Update the firewall script which "--option ! xxx" is deprecated and should
    replaced by "! --option xxx".
  * Update the firewall script to support the serviceclass concept.
  * Update weblogin which should send the class-of-service name when RADIUS
    return this attribute back.
  * src/include has been removed (no needs).

27 files changed:
configure.ac
src/Makefile.am
src/include/linux/netfilter_ipv4/ip_set.h [deleted file]
src/include/linux/netfilter_ipv4/ip_set_rahunas.h [deleted file]
src/ipset/ip_set.h
src/ipset/ip_set_hashes.h [new file with mode: 0644]
src/ipset/ip_set_rahunas_ipiphash.h [new file with mode: 0644]
src/rahunasd.c
src/rahunasd.h
src/rh-config.c
src/rh-config.h
src/rh-ipset.c
src/rh-ipset.h
src/rh-server.c
src/rh-server.h
src/rh-serviceclass.c [new file with mode: 0644]
src/rh-serviceclass.h [new file with mode: 0644]
src/rh-task-dbset.c
src/rh-task-memset.c
src/rh-task-serviceclass.c [new file with mode: 0644]
src/rh-task-serviceclass.h [new file with mode: 0644]
src/rh-task.c
src/rh-task.h
src/rh-xmlrpc-server.c
tools/rahunas-firewall.in
tools/rahunas-vipmap.in [deleted file]
weblogin/login.php

index 2fadb61..2fea693 100644 (file)
@@ -61,7 +61,6 @@ AC_CONFIG_FILES([
   tools/Makefile
   tools/rahunas-firewall
   tools/rahunas-bandwidth
-  tools/rahunas-vipmap
   tools/rahunas-weblogin-config-update
   example/Makefile
   example/rahunas.default
index c069b7b..8ded29d 100644 (file)
@@ -8,7 +8,6 @@ AM_CFLAGS = \
   $(LIBGNET_CFLAGS) \
   $(LIBGDA_CFLAGS) \
   -I$(top_srcdir)/src/ \
-  -I$(top_srcdir)/src/include/ \
   -DRAHUNAS_VERSION=\"$(RAHUNAS_VERSION)\" \
   -DPROGRAM=\"$(PROGRAM)\" \
   -DIPSET_VERSION=\"$(IPSET_VERSION)\" \
@@ -44,17 +43,16 @@ rahunasd_SOURCES = \
   rh-task-dbset.h \
   rh-task-bandwidth.c \
   rh-task-bandwidth.h \
+  rh-task-serviceclass.c \
+  rh-task-serviceclass.h \
   rh-radius.h \
   rh-config.c \
-  rh-config.h
+  rh-config.h \
+  rh-serviceclass.h \
+  rh-serviceclass.c
 
 rahunasd_LDADD =  \
   $(top_builddir)/xmlrpc/libgnetxmlrpc.a \
   $(top_builddir)/lcfg/liblcfg.a \
   $(LIBGNET_LIBS) \
   $(LIBGDA_LIBS)
-
-noinst_HEADERS = \
-  include/linux/netfilter_ipv4/ip_set.h \
-  include/linux/netfilter_ipv4/ip_set_rahunas.h
-
diff --git a/src/include/linux/netfilter_ipv4/ip_set.h b/src/include/linux/netfilter_ipv4/ip_set.h
deleted file mode 100644 (file)
index b8c7202..0000000
+++ /dev/null
@@ -1,499 +0,0 @@
-#ifndef _IP_SET_H
-#define _IP_SET_H
-
-/* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
- *                         Patrick Schaaf <bof@bof.de>
- *                         Martin Josefsson <gandalf@wlug.westbo.se>
- * Copyright (C) 2003-2004 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.  
- */
-
-#if 0
-#define IP_SET_DEBUG
-#endif
-
-/*
- * A sockopt of such quality has hardly ever been seen before on the open
- * market!  This little beauty, hardly ever used: above 64, so it's
- * traditionally used for firewalling, not touched (even once!) by the
- * 2.0, 2.2 and 2.4 kernels!
- *
- * Comes with its own certificate of authenticity, valid anywhere in the
- * Free world!
- *
- * Rusty, 19.4.2000
- */
-#define SO_IP_SET              83
-
-/*
- * Heavily modify by Joakim Axelsson 08.03.2002
- * - Made it more modulebased
- *
- * Additional heavy modifications by Jozsef Kadlecsik 22.02.2004
- * - bindings added
- * - in order to "deal with" backward compatibility, renamed to ipset
- */
-
-/* 
- * Used so that the kernel module and ipset-binary can match their versions 
- */
-#define IP_SET_PROTOCOL_VERSION 2
-
-#define IP_SET_MAXNAMELEN 32   /* set names and set typenames */
-
-/* Lets work with our own typedef for representing an IP address.
- * We hope to make the code more portable, possibly to IPv6...
- *
- * The representation works in HOST byte order, because most set types
- * will perform arithmetic operations and compare operations.
- * 
- * For now the type is an uint32_t.
- *
- * Make sure to ONLY use the functions when translating and parsing
- * in order to keep the host byte order and make it more portable:
- *  parse_ip()
- *  parse_mask()
- *  parse_ipandmask()
- *  ip_tostring()
- * (Joakim: where are they???)
- */
-
-typedef uint32_t ip_set_ip_t;
-
-/* Sets are identified by an id in kernel space. Tweak with ip_set_id_t
- * and IP_SET_INVALID_ID if you want to increase the max number of sets.
- */
-typedef uint16_t ip_set_id_t;
-
-#define IP_SET_INVALID_ID      65535
-
-/* How deep we follow bindings */
-#define IP_SET_MAX_BINDINGS    6
-
-/*
- * Option flags for kernel operations (ipt_set_info)
- */
-#define IPSET_SRC              0x01    /* Source match/add */
-#define IPSET_DST              0x02    /* Destination match/add */
-#define IPSET_MATCH_INV                0x04    /* Inverse matching */
-
-/*
- * Set features
- */
-#define IPSET_TYPE_IP          0x01    /* IP address type of set */
-#define IPSET_TYPE_PORT                0x02    /* Port type of set */
-#define IPSET_DATA_SINGLE      0x04    /* Single data storage */
-#define IPSET_DATA_DOUBLE      0x08    /* Double data storage */
-
-/* Reserved keywords */
-#define IPSET_TOKEN_DEFAULT    ":default:"
-#define IPSET_TOKEN_ALL                ":all:"
-
-/* SO_IP_SET operation constants, and their request struct types.
- *
- * Operation ids:
- *       0-99:  commands with version checking
- *     100-199: add/del/test/bind/unbind
- *     200-299: list, save, restore
- */
-
-/* Single shot operations: 
- * version, create, destroy, flush, rename and swap 
- *
- * Sets are identified by name.
- */
-
-#define IP_SET_REQ_STD         \
-       unsigned op;            \
-       unsigned version;       \
-       char name[IP_SET_MAXNAMELEN]
-
-#define IP_SET_OP_CREATE       0x00000001      /* Create a new (empty) set */
-struct ip_set_req_create {
-       IP_SET_REQ_STD;
-       char typename[IP_SET_MAXNAMELEN];
-};
-
-#define IP_SET_OP_DESTROY      0x00000002      /* Remove a (empty) set */
-struct ip_set_req_std {
-       IP_SET_REQ_STD;
-};
-
-#define IP_SET_OP_FLUSH                0x00000003      /* Remove all IPs in a set */
-/* Uses ip_set_req_std */
-
-#define IP_SET_OP_RENAME       0x00000004      /* Rename a set */
-/* Uses ip_set_req_create */
-
-#define IP_SET_OP_SWAP         0x00000005      /* Swap two sets */
-/* Uses ip_set_req_create */
-
-union ip_set_name_index {
-       char name[IP_SET_MAXNAMELEN];
-       ip_set_id_t index;
-};
-
-#define IP_SET_OP_GET_BYNAME   0x00000006      /* Get set index by name */
-struct ip_set_req_get_set {
-       unsigned op;
-       unsigned version;
-       union ip_set_name_index set;
-};
-
-#define IP_SET_OP_GET_BYINDEX  0x00000007      /* Get set name by index */
-/* Uses ip_set_req_get_set */
-
-#define IP_SET_OP_VERSION      0x00000100      /* Ask kernel version */
-struct ip_set_req_version {
-       unsigned op;
-       unsigned version;
-};
-
-/* Double shots operations: 
- * add, del, test, bind and unbind.
- *
- * First we query the kernel to get the index and type of the target set,
- * then issue the command. Validity of IP is checked in kernel in order
- * to minimalize sockopt operations.
- */
-
-/* Get minimal set data for add/del/test/bind/unbind IP */
-#define IP_SET_OP_ADT_GET      0x00000010      /* Get set and type */
-struct ip_set_req_adt_get {
-       unsigned op;
-       unsigned version;
-       union ip_set_name_index set;
-       char typename[IP_SET_MAXNAMELEN];
-};
-
-#define IP_SET_REQ_BYINDEX     \
-       unsigned op;            \
-       ip_set_id_t index;
-
-struct ip_set_req_adt {
-       IP_SET_REQ_BYINDEX;
-};
-
-#define IP_SET_OP_ADD_IP       0x00000101      /* Add an IP to a set */
-/* Uses ip_set_req_adt, with type specific addage */
-
-#define IP_SET_OP_DEL_IP       0x00000102      /* Remove an IP from a set */
-/* Uses ip_set_req_adt, with type specific addage */
-
-#define IP_SET_OP_TEST_IP      0x00000103      /* Test an IP in a set */
-/* Uses ip_set_req_adt, with type specific addage */
-
-#define IP_SET_OP_BIND_SET     0x00000104      /* Bind an IP to a set */
-/* Uses ip_set_req_bind, with type specific addage */
-struct ip_set_req_bind {
-       IP_SET_REQ_BYINDEX;
-       char binding[IP_SET_MAXNAMELEN];
-};
-
-#define IP_SET_OP_UNBIND_SET   0x00000105      /* Unbind an IP from a set */
-/* Uses ip_set_req_bind, with type speficic addage 
- * index = 0 means unbinding for all sets */
-
-#define IP_SET_OP_TEST_BIND_SET        0x00000106      /* Test binding an IP to a set */
-/* Uses ip_set_req_bind, with type specific addage */
-
-/* Multiple shots operations: list, save, restore.
- *
- * - check kernel version and query the max number of sets
- * - get the basic information on all sets
- *   and size required for the next step
- * - get actual set data: header, data, bindings
- */
-
-/* Get max_sets and the index of a queried set
- */
-#define IP_SET_OP_MAX_SETS     0x00000020
-struct ip_set_req_max_sets {
-       unsigned op;
-       unsigned version;
-       ip_set_id_t max_sets;           /* max_sets */
-       ip_set_id_t sets;               /* real number of sets */
-       union ip_set_name_index set;    /* index of set if name used */
-};
-
-/* Get the id and name of the sets plus size for next step */
-#define IP_SET_OP_LIST_SIZE    0x00000201
-#define IP_SET_OP_SAVE_SIZE    0x00000202
-struct ip_set_req_setnames {
-       unsigned op;
-       ip_set_id_t index;              /* set to list/save */
-       size_t size;                    /* size to get setdata/bindings */
-       /* followed by sets number of struct ip_set_name_list */
-};
-
-struct ip_set_name_list {
-       char name[IP_SET_MAXNAMELEN];
-       char typename[IP_SET_MAXNAMELEN];
-       ip_set_id_t index;
-       ip_set_id_t id;
-};
-
-/* The actual list operation */
-#define IP_SET_OP_LIST         0x00000203
-struct ip_set_req_list {
-       IP_SET_REQ_BYINDEX;
-       /* sets number of struct ip_set_list in reply */ 
-};
-
-struct ip_set_list {
-       ip_set_id_t index;
-       ip_set_id_t binding;
-       u_int32_t ref;
-       size_t header_size;     /* Set header data of header_size */
-       size_t members_size;    /* Set members data of members_size */
-       size_t bindings_size;   /* Set bindings data of bindings_size */
-};
-
-struct ip_set_hash_list {
-       ip_set_ip_t ip;
-       ip_set_id_t binding;
-};
-
-/* The save operation */
-#define IP_SET_OP_SAVE         0x00000204
-/* Uses ip_set_req_list, in the reply replaced by
- * sets number of struct ip_set_save plus a marker
- * ip_set_save followed by ip_set_hash_save structures.
- */
-struct ip_set_save {
-       ip_set_id_t index;
-       ip_set_id_t binding;
-       size_t header_size;     /* Set header data of header_size */
-       size_t members_size;    /* Set members data of members_size */
-};
-
-/* At restoring, ip == 0 means default binding for the given set: */
-struct ip_set_hash_save {
-       ip_set_ip_t ip;
-       ip_set_id_t id;
-       ip_set_id_t binding;
-};
-
-/* The restore operation */
-#define IP_SET_OP_RESTORE      0x00000205
-/* Uses ip_set_req_setnames followed by ip_set_restore structures
- * plus a marker ip_set_restore, followed by ip_set_hash_save 
- * structures.
- */
-struct ip_set_restore {
-       char name[IP_SET_MAXNAMELEN];
-       char typename[IP_SET_MAXNAMELEN];
-       ip_set_id_t index;
-       size_t header_size;     /* Create data of header_size */
-       size_t members_size;    /* Set members data of members_size */
-};
-
-static inline int bitmap_bytes(ip_set_ip_t a, ip_set_ip_t b)
-{
-       return 4 * ((((b - a + 8) / 8) + 3) / 4);
-}
-
-#ifdef __KERNEL__
-#include <linux/netfilter_ipv4/ip_set_compat.h>
-
-#define ip_set_printk(format, args...)                         \
-       do {                                                    \
-               printk("%s: %s: ", __FILE__, __FUNCTION__);     \
-               printk(format "\n" , ## args);                  \
-       } while (0)
-
-#if defined(IP_SET_DEBUG)
-#define DP(format, args...)                                    \
-       do {                                                    \
-               printk("%s: %s (DBG): ", __FILE__, __FUNCTION__);\
-               printk(format "\n" , ## args);                  \
-       } while (0)
-#define IP_SET_ASSERT(x)                                       \
-       do {                                                    \
-               if (!(x))                                       \
-                       printk("IP_SET_ASSERT: %s:%i(%s)\n",    \
-                               __FILE__, __LINE__, __FUNCTION__); \
-       } while (0)
-#else
-#define DP(format, args...)
-#define IP_SET_ASSERT(x)
-#endif
-
-struct ip_set;
-
-/*
- * The ip_set_type definition - one per set type, e.g. "ipmap".
- *
- * Each individual set has a pointer, set->type, going to one
- * of these structures. Function pointers inside the structure implement
- * the real behaviour of the sets.
- *
- * If not mentioned differently, the implementation behind the function
- * pointers of a set_type, is expected to return 0 if ok, and a negative
- * errno (e.g. -EINVAL) on error.
- */
-struct ip_set_type {
-       struct list_head list;  /* next in list of set types */
-
-       /* test for IP in set (kernel: iptables -m set src|dst)
-        * return 0 if not in set, 1 if in set.
-        */
-       int (*testip_kernel) (struct ip_set *set,
-                             const struct sk_buff * skb, 
-                             ip_set_ip_t *ip,
-                             const u_int32_t *flags,
-                             unsigned char index);
-
-       /* test for IP in set (userspace: ipset -T set IP)
-        * return 0 if not in set, 1 if in set.
-        */
-       int (*testip) (struct ip_set *set,
-                      const void *data, size_t size,
-                      ip_set_ip_t *ip);
-
-       /*
-        * Size of the data structure passed by when
-        * adding/deletin/testing an entry.
-        */
-       size_t reqsize;
-
-       /* Add IP into set (userspace: ipset -A set IP)
-        * Return -EEXIST if the address is already in the set,
-        * and -ERANGE if the address lies outside the set bounds.
-        * If the address was not already in the set, 0 is returned.
-        */
-       int (*addip) (struct ip_set *set, 
-                     const void *data, size_t size,
-                     ip_set_ip_t *ip);
-
-       /* Add IP into set (kernel: iptables ... -j SET set src|dst)
-        * Return -EEXIST if the address is already in the set,
-        * and -ERANGE if the address lies outside the set bounds.
-        * If the address was not already in the set, 0 is returned.
-        */
-       int (*addip_kernel) (struct ip_set *set,
-                            const struct sk_buff * skb, 
-                            ip_set_ip_t *ip,
-                            const u_int32_t *flags,
-                            unsigned char index);
-
-       /* remove IP from set (userspace: ipset -D set --entry x)
-        * Return -EEXIST if the address is NOT in the set,
-        * and -ERANGE if the address lies outside the set bounds.
-        * If the address really was in the set, 0 is returned.
-        */
-       int (*delip) (struct ip_set *set, 
-                     const void *data, size_t size,
-                     ip_set_ip_t *ip);
-
-       /* remove IP from set (kernel: iptables ... -j SET --entry x)
-        * Return -EEXIST if the address is NOT in the set,
-        * and -ERANGE if the address lies outside the set bounds.
-        * If the address really was in the set, 0 is returned.
-        */
-       int (*delip_kernel) (struct ip_set *set,
-                            const struct sk_buff * skb, 
-                            ip_set_ip_t *ip,
-                            const u_int32_t *flags,
-                            unsigned char index);
-
-       /* new set creation - allocated type specific items
-        */
-       int (*create) (struct ip_set *set,
-                      const void *data, size_t size);
-
-       /* retry the operation after successfully tweaking the set
-        */
-       int (*retry) (struct ip_set *set);
-
-       /* set destruction - free type specific items
-        * There is no return value.
-        * Can be called only when child sets are destroyed.
-        */
-       void (*destroy) (struct ip_set *set);
-
-       /* set flushing - reset all bits in the set, or something similar.
-        * There is no return value.
-        */
-       void (*flush) (struct ip_set *set);
-
-       /* Listing: size needed for header
-        */
-       size_t header_size;
-
-       /* Listing: Get the header
-        *
-        * Fill in the information in "data".
-        * This function is always run after list_header_size() under a 
-        * writelock on the set. Therefor is the length of "data" always 
-        * correct. 
-        */
-       void (*list_header) (const struct ip_set *set, 
-                            void *data);
-
-       /* Listing: Get the size for the set members
-        */
-       int (*list_members_size) (const struct ip_set *set);
-
-       /* Listing: Get the set members
-        *
-        * Fill in the information in "data".
-        * This function is always run after list_member_size() under a 
-        * writelock on the set. Therefor is the length of "data" always 
-        * correct. 
-        */
-       void (*list_members) (const struct ip_set *set,
-                             void *data);
-
-       char typename[IP_SET_MAXNAMELEN];
-       unsigned char features;
-       int protocol_version;
-
-       /* Set this to THIS_MODULE if you are a module, otherwise NULL */
-       struct module *me;
-};
-
-extern int ip_set_register_set_type(struct ip_set_type *set_type);
-extern void ip_set_unregister_set_type(struct ip_set_type *set_type);
-
-/* A generic ipset */
-struct ip_set {
-       char name[IP_SET_MAXNAMELEN];   /* the name of the set */
-       rwlock_t lock;                  /* lock for concurrency control */
-       ip_set_id_t id;                 /* set id for swapping */
-       ip_set_id_t binding;            /* default binding for the set */
-       atomic_t ref;                   /* in kernel and in hash references */
-       struct ip_set_type *type;       /* the set types */
-       void *data;                     /* pooltype specific data */
-};
-
-/* Structure to bind set elements to sets */
-struct ip_set_hash {
-       struct list_head list;          /* list of clashing entries in hash */
-       ip_set_ip_t ip;                 /* ip from set */
-       ip_set_id_t id;                 /* set id */
-       ip_set_id_t binding;            /* set we bind the element to */
-};
-
-/* register and unregister set references */
-extern ip_set_id_t ip_set_get_byname(const char name[IP_SET_MAXNAMELEN]);
-extern ip_set_id_t ip_set_get_byindex(ip_set_id_t id);
-extern void ip_set_put(ip_set_id_t id);
-
-/* API for iptables set match, and SET target */
-extern void ip_set_addip_kernel(ip_set_id_t id,
-                               const struct sk_buff *skb,
-                               const u_int32_t *flags);
-extern void ip_set_delip_kernel(ip_set_id_t id,
-                               const struct sk_buff *skb,
-                               const u_int32_t *flags);
-extern int ip_set_testip_kernel(ip_set_id_t id,
-                               const struct sk_buff *skb,
-                               const u_int32_t *flags);
-
-#endif                         /* __KERNEL__ */
-
-#endif /*_IP_SET_H*/
diff --git a/src/include/linux/netfilter_ipv4/ip_set_rahunas.h b/src/include/linux/netfilter_ipv4/ip_set_rahunas.h
deleted file mode 100644 (file)
index 2ca11b6..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef __IP_SET_RAHUNAS_H
-#define __IP_SET_RAHUNAS_H
-
-#ifdef __KERNEL__
-#  include <linux/time.h>
-#else
-#  include <time.h>
-#endif
-
-#include <linux/netfilter_ipv4/ip_set.h>
-
-#define SETTYPE_NAME "rahunas"
-#define MAX_RANGE 0x0000FFFF
-
-/* general flags */
-#define IPSET_RAHUNAS_MATCHUNSET       1
-
-/* per ip flags */
-#define IPSET_RAHUNAS_ISSET    1
-
-struct ip_set_rahunasmap {
-       void *members;                  /* the rahunas proper */
-       ip_set_ip_t first_ip;           /* host byte order, included in range */
-       ip_set_ip_t last_ip;            /* host byte order, included in range */
-       u_int32_t flags;
-};
-
-struct ip_set_req_rahunas_create {
-       ip_set_ip_t from;
-       ip_set_ip_t to;
-       u_int32_t flags;
-};
-
-struct ip_set_req_rahunas {
-       ip_set_ip_t ip;
-       unsigned char ethernet[ETH_ALEN];
-};
-
-struct ip_set_rahunas {
-       unsigned short flags;
-       unsigned char ethernet[ETH_ALEN];
-       time_t timestamp;
-};
-
-#endif /* __IP_SET_RAHUNAS_H */
index 07d61a0..227f0ba 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _IP_SET_H
 #define _IP_SET_H
 
+#include <inttypes.h>
+
 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
  *                         Patrick Schaaf <bof@bof.de>
  *                         Martin Josefsson <gandalf@wlug.westbo.se>
diff --git a/src/ipset/ip_set_hashes.h b/src/ipset/ip_set_hashes.h
new file mode 100644 (file)
index 0000000..8eeced3
--- /dev/null
@@ -0,0 +1,314 @@
+#ifndef __IP_SET_HASHES_H
+#define __IP_SET_HASHES_H
+
+#define initval_t uint32_t
+
+/* Macros to generate functions */
+
+#ifdef __KERNEL__
+#define HASH_RETRY0(type, dtype, cond)                                 \
+static int                                                             \
+type##_retry(struct ip_set *set)                                       \
+{                                                                      \
+       struct ip_set_##type *map = set->data, *tmp;                    \
+       dtype *elem;                                                    \
+       void *members;                                                  \
+       u_int32_t i, hashsize = map->hashsize;                          \
+       int res;                                                        \
+                                                                       \
+       if (map->resize == 0)                                           \
+               return -ERANGE;                                         \
+                                                                       \
+    again:                                                             \
+       res = 0;                                                        \
+                                                                       \
+       /* Calculate new hash size */                                   \
+       hashsize += (hashsize * map->resize)/100;                       \
+       if (hashsize == map->hashsize)                                  \
+               hashsize++;                                             \
+                                                                       \
+       ip_set_printk("rehashing of set %s triggered: "                 \
+                     "hashsize grows from %lu to %lu",                 \
+                     set->name,                                        \
+                     (long unsigned)map->hashsize,                     \
+                     (long unsigned)hashsize);                         \
+                                                                       \
+       tmp = kmalloc(sizeof(struct ip_set_##type)                      \
+                     + map->probes * sizeof(initval_t), GFP_ATOMIC);   \
+       if (!tmp) {                                                     \
+               DP("out of memory for %zu bytes",                       \
+                  sizeof(struct ip_set_##type)                         \
+                  + map->probes * sizeof(initval_t));                  \
+               return -ENOMEM;                                         \
+       }                                                               \
+       tmp->members = harray_malloc(hashsize, sizeof(dtype), GFP_ATOMIC);\
+       if (!tmp->members) {                                            \
+               DP("out of memory for %zu bytes", hashsize * sizeof(dtype));\
+               kfree(tmp);                                             \
+               return -ENOMEM;                                         \
+       }                                                               \
+       tmp->hashsize = hashsize;                                       \
+       tmp->elements = 0;                                              \
+       tmp->probes = map->probes;                                      \
+       tmp->resize = map->resize;                                      \
+       memcpy(tmp->initval, map->initval, map->probes * sizeof(initval_t));\
+       __##type##_retry(tmp, map);                                     \
+                                                                       \
+       write_lock_bh(&set->lock);                                      \
+       map = set->data; /* Play safe */                                \
+       for (i = 0; i < map->hashsize && res == 0; i++) {               \
+               elem = HARRAY_ELEM(map->members, dtype *, i);           \
+               if (cond)                                               \
+                       res = __##type##_add(tmp, elem);                \
+       }                                                               \
+       if (res) {                                                      \
+               /* Failure, try again */                                \
+               write_unlock_bh(&set->lock);                            \
+               harray_free(tmp->members);                              \
+               kfree(tmp);                                             \
+               goto again;                                             \
+       }                                                               \
+                                                                       \
+       /* Success at resizing! */                                      \
+       members = map->members;                                         \
+                                                                       \
+       map->hashsize = tmp->hashsize;                                  \
+       map->members = tmp->members;                                    \
+       write_unlock_bh(&set->lock);                                    \
+                                                                       \
+       harray_free(members);                                           \
+       kfree(tmp);                                                     \
+                                                                       \
+       return 0;                                                       \
+}
+
+#define HASH_RETRY(type, dtype)                                                \
+       HASH_RETRY0(type, dtype, *elem)
+
+#define HASH_RETRY2(type, dtype)                                               \
+       HASH_RETRY0(type, dtype, elem->ip || elem->ip1)
+
+#define HASH_CREATE(type, dtype)                                       \
+static int                                                             \
+type##_create(struct ip_set *set, const void *data, u_int32_t size)    \
+{                                                                      \
+       const struct ip_set_req_##type##_create *req = data;            \
+       struct ip_set_##type *map;                                      \
+       uint16_t i;                                                     \
+                                                                       \
+       if (req->hashsize < 1) {                                        \
+               ip_set_printk("hashsize too small");                    \
+               return -ENOEXEC;                                        \
+       }                                                               \
+                                                                       \
+       if (req->probes < 1) {                                          \
+               ip_set_printk("probes too small");                      \
+               return -ENOEXEC;                                        \
+       }                                                               \
+                                                                       \
+       map = kmalloc(sizeof(struct ip_set_##type)                      \
+                     + req->probes * sizeof(initval_t), GFP_KERNEL);   \
+       if (!map) {                                                     \
+               DP("out of memory for %zu bytes",                       \
+                  sizeof(struct ip_set_##type)                         \
+                  + req->probes * sizeof(initval_t));                  \
+               return -ENOMEM;                                         \
+       }                                                               \
+       for (i = 0; i < req->probes; i++)                               \
+               get_random_bytes(((initval_t *) map->initval)+i, 4);    \
+       map->elements = 0;                                              \
+       map->hashsize = req->hashsize;                                  \
+       map->probes = req->probes;                                      \
+       map->resize = req->resize;                                      \
+       if (__##type##_create(req, map)) {                              \
+               kfree(map);                                             \
+               return -ENOEXEC;                                        \
+       }                                                               \
+       map->members = harray_malloc(map->hashsize, sizeof(dtype), GFP_KERNEL);\
+       if (!map->members) {                                            \
+               DP("out of memory for %zu bytes", map->hashsize * sizeof(dtype));\
+               kfree(map);                                             \
+               return -ENOMEM;                                         \
+       }                                                               \
+                                                                       \
+       set->data = map;                                                \
+       return 0;                                                       \
+}
+
+#define HASH_DESTROY(type)                                             \
+static void                                                            \
+type##_destroy(struct ip_set *set)                                     \
+{                                                                      \
+       struct ip_set_##type *map = set->data;                          \
+                                                                       \
+       harray_free(map->members);                                      \
+       kfree(map);                                                     \
+                                                                       \
+       set->data = NULL;                                               \
+}
+
+#define HASH_FLUSH(type, dtype)                                                \
+static void                                                            \
+type##_flush(struct ip_set *set)                                       \
+{                                                                      \
+       struct ip_set_##type *map = set->data;                          \
+       harray_flush(map->members, map->hashsize, sizeof(dtype));       \
+       map->elements = 0;                                              \
+}
+
+#define HASH_FLUSH_CIDR(type, dtype)                                   \
+static void                                                            \
+type##_flush(struct ip_set *set)                                       \
+{                                                                      \
+       struct ip_set_##type *map = set->data;                          \
+       harray_flush(map->members, map->hashsize, sizeof(dtype));       \
+       memset(map->cidr, 0, sizeof(map->cidr));                        \
+       memset(map->nets, 0, sizeof(map->nets));                        \
+       map->elements = 0;                                              \
+}
+
+#define HASH_LIST_HEADER(type)                                         \
+static void                                                            \
+type##_list_header(const struct ip_set *set, void *data)               \
+{                                                                      \
+       const struct ip_set_##type *map = set->data;                    \
+       struct ip_set_req_##type##_create *header = data;               \
+                                                                       \
+       header->hashsize = map->hashsize;                               \
+       header->probes = map->probes;                                   \
+       header->resize = map->resize;                                   \
+       __##type##_list_header(map, header);                            \
+}
+
+#define HASH_LIST_MEMBERS_SIZE(type, dtype)                            \
+static int                                                             \
+type##_list_members_size(const struct ip_set *set, char dont_align)    \
+{                                                                      \
+       const struct ip_set_##type *map = set->data;                    \
+                                                                       \
+       return (map->elements * IPSET_VALIGN(sizeof(dtype), dont_align));\
+}
+
+#define HASH_LIST_MEMBERS(type, dtype)                                 \
+static void                                                            \
+type##_list_members(const struct ip_set *set, void *data, char dont_align)\
+{                                                                      \
+       const struct ip_set_##type *map = set->data;                    \
+       dtype *elem, *d;                                                \
+       uint32_t i, n = 0;                                              \
+                                                                       \
+       for (i = 0; i < map->hashsize; i++) {                           \
+               elem = HARRAY_ELEM(map->members, dtype *, i);           \
+               if (*elem) {                                            \
+                       d = data + n * IPSET_VALIGN(sizeof(dtype), dont_align);\
+                       *d = *elem;                                     \
+                       n++;                                            \
+               }                                                       \
+       }                                                               \
+}
+
+#define HASH_LIST_MEMBERS_MEMCPY(type, dtype, nonzero)                 \
+static void                                                            \
+type##_list_members(const struct ip_set *set, void *data, char dont_align)\
+{                                                                      \
+       const struct ip_set_##type *map = set->data;                    \
+       dtype *elem;                                                    \
+       uint32_t i, n = 0;                                              \
+                                                                       \
+       for (i = 0; i < map->hashsize; i++) {                           \
+               elem = HARRAY_ELEM(map->members, dtype *, i);           \
+               if (nonzero) {                                          \
+                       memcpy(data + n * IPSET_VALIGN(sizeof(dtype), dont_align),\
+                              elem, sizeof(dtype));                    \
+                       n++;                                            \
+               }                                                       \
+       }                                                               \
+}
+
+#define IP_SET_RTYPE(type, __features)                                 \
+struct ip_set_type ip_set_##type = {                                   \
+       .typename               = #type,                                \
+       .features               = __features,                           \
+       .protocol_version       = IP_SET_PROTOCOL_VERSION,              \
+       .create                 = &type##_create,                       \
+       .retry                  = &type##_retry,                        \
+       .destroy                = &type##_destroy,                      \
+       .flush                  = &type##_flush,                        \
+       .reqsize                = sizeof(struct ip_set_req_##type),     \
+       .addip                  = &type##_uadd,                         \
+       .addip_kernel           = &type##_kadd,                         \
+       .delip                  = &type##_udel,                         \
+       .delip_kernel           = &type##_kdel,                         \
+       .testip                 = &type##_utest,                        \
+       .testip_kernel          = &type##_ktest,                        \
+       .header_size            = sizeof(struct ip_set_req_##type##_create),\
+       .list_header            = &type##_list_header,                  \
+       .list_members_size      = &type##_list_members_size,            \
+       .list_members           = &type##_list_members,                 \
+       .me                     = THIS_MODULE,                          \
+};
+
+/* Helper functions */
+static inline void
+add_cidr_size(uint8_t *cidr, uint8_t size)
+{
+       uint8_t next;
+       int i;
+       
+       for (i = 0; i < 30 && cidr[i]; i++) {
+               if (cidr[i] < size) {
+                       next = cidr[i];
+                       cidr[i] = size;
+                       size = next;
+               }
+       }
+       if (i < 30)
+               cidr[i] = size;
+}
+
+static inline void
+del_cidr_size(uint8_t *cidr, uint8_t size)
+{
+       int i;
+       
+       for (i = 0; i < 29 && cidr[i]; i++) {
+               if (cidr[i] == size)
+                       cidr[i] = size = cidr[i+1];
+       }
+       cidr[29] = 0;
+}
+#else
+#include <arpa/inet.h>
+#endif /* __KERNEL */
+
+#ifndef UINT16_MAX
+#define UINT16_MAX 65535
+#endif
+
+static unsigned char shifts[] = {255, 253, 249, 241, 225, 193, 129, 1};
+
+static inline ip_set_ip_t 
+pack_ip_cidr(ip_set_ip_t ip, unsigned char cidr)
+{
+       ip_set_ip_t addr, *paddr = &addr;
+       unsigned char n, t, *a;
+
+       addr = htonl(ip & (0xFFFFFFFF << (32 - (cidr))));
+#ifdef __KERNEL__
+       DP("ip:%u.%u.%u.%u/%u", NIPQUAD(addr), cidr);
+#endif
+       n = cidr / 8;
+       t = cidr % 8;   
+       a = &((unsigned char *)paddr)[n];
+       *a = *a /(1 << (8 - t)) + shifts[t];
+#ifdef __KERNEL__
+       DP("n: %u, t: %u, a: %u", n, t, *a);
+       DP("ip:%u.%u.%u.%u/%u, %u.%u.%u.%u",
+          HIPQUAD(ip), cidr, NIPQUAD(addr));
+#endif
+
+       return ntohl(addr);
+}
+
+
+#endif /* __IP_SET_HASHES_H */
diff --git a/src/ipset/ip_set_rahunas_ipiphash.h b/src/ipset/ip_set_rahunas_ipiphash.h
new file mode 100644 (file)
index 0000000..d850929
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __IP_SET_RAHUNAS_IPIPHASH_H
+#define __IP_SET_RAHUNAS_IPIPHASH_H
+
+#include <asm/types.h>
+
+#include "ip_set.h"
+#include "ip_set_hashes.h"
+
+#define SETTYPE_NAME           "rahunas_ipiphash"
+
+struct rahunas_ipip {
+  ip_set_ip_t ip;
+  ip_set_ip_t ip1;
+};
+
+struct ip_set_rahunas_ipiphash {
+       struct ip_set_rahunas_ipip *members;            /* the ipiphash proper */
+       uint32_t elements;              /* number of elements */
+       uint32_t hashsize;              /* hash size */
+       uint16_t probes;                /* max number of probes  */
+       uint16_t resize;                /* resize factor in percent */
+       initval_t initval[0];           /* initvals for jhash_1word */
+};
+
+struct ip_set_req_rahunas_ipiphash_create {
+       uint32_t hashsize;
+       uint16_t probes;
+       uint16_t resize;
+};
+
+struct ip_set_req_rahunas_ipiphash {
+       ip_set_ip_t ip;
+  ip_set_ip_t ip1;
+};
+
+extern __u32 rahunas_ipiphash_id(struct ip_set *set, ip_set_ip_t ip);
+
+#endif /* __IP_SET_RAHUNAS_IPIPHASH_H */
index c793ace..db0c728 100644 (file)
@@ -28,6 +28,7 @@ pid_t pid, sid;
 
 struct main_server rh_main_server_instance = {
   .vserver_list = NULL,
+  .serviceclass_list = NULL,
   .task_list = NULL,
 };
 struct main_server *rh_main_server = &rh_main_server_instance;
@@ -176,6 +177,18 @@ void rh_reload()
     exit(EXIT_FAILURE);
   }
 
+  /* Get serviceclass config, again */
+  if (rh_main_server->main_config->serviceclass_conf_dir != NULL) {
+    get_serviceclass_config(rh_main_server->main_config->serviceclass_conf_dir,
+                            rh_main_server);
+  } else {
+    syslog(LOG_ERR, "The main configuration file is incompleted, lack of serviceclass_conf_dir\n");
+    exit(EXIT_FAILURE);
+  }
+
+  walk_through_serviceclass(&serviceclass_reload, rh_main_server);
+  serviceclass_unused_cleanup(rh_main_server);
+
   walk_through_vserver(&vserver_reload, rh_main_server);
   vserver_unused_cleanup(rh_main_server);
   
@@ -283,6 +296,12 @@ void rh_free_member (struct rahunas_member *member)
 
   if (member->session_id && member->session_id != termstring)
     free(member->session_id);
+
+  if (member->serviceclass_name && member->serviceclass_name != termstring)
+    free(member->serviceclass_name);
+
+  if (member->mapping_ip && member->mapping_ip != termstring)
+    free(member->mapping_ip);
 }
 
 
@@ -298,10 +317,12 @@ int main(int argc, char **argv)
 
   union rahunas_config rh_main_config = {
     .rh_main.conf_dir = NULL,
+    .rh_main.serviceclass_conf_dir = NULL,
     .rh_main.log_file = NULL,
     .rh_main.dhcp = NULL,
     .rh_main.polling_interval = POLLING,
     .rh_main.bandwidth_shape = BANDWIDTH_SHAPE,
+    .rh_main.serviceclass = 0,
   };
 
   GNetXmlRpcServer *server = NULL;
@@ -342,6 +363,18 @@ int main(int argc, char **argv)
     exit(EXIT_FAILURE);
   }
 
+  if (rh_main_server->main_config->serviceclass) {
+    /* Get serviceclass config */
+    if (rh_main_server->main_config->serviceclass_conf_dir != NULL) {
+      get_serviceclass_config(rh_main_server->main_config->serviceclass_conf_dir,
+                              rh_main_server);
+    } else {
+      syslog(LOG_ERR, "The main configuration file is incompleted, lack of serviceclass_conf_dir\n");
+      exit(EXIT_FAILURE);
+    }
+  }
+
+
   snprintf(version, sizeof (version), "Starting %s - Version %s", PROGRAM, 
            RAHUNAS_VERSION);
   logmsg(RH_LOG_NORMAL, version);
@@ -349,6 +382,9 @@ int main(int argc, char **argv)
   rh_task_register(rh_main_server);
   rh_task_startservice(rh_main_server);
 
+  if (rh_main_server->main_config->serviceclass)
+    walk_through_serviceclass(&serviceclass_init, rh_main_server);
+
   walk_through_vserver(&rh_task_init, rh_main_server);
 
   gnet_init();
index 8582304..f48f8d1 100644 (file)
@@ -58,6 +58,9 @@ struct rahunas_member {
   long bandwidth_max_down;
   long bandwidth_max_up;
   unsigned short bandwidth_slot_id;
+  char *serviceclass_name;
+  uint32_t serviceclass_slot_id;
+  char *mapping_ip;
   char *username;
   char *session_id;
   unsigned char mac_address[ETH_ALEN];
index 199fba2..395e481 100755 (executable)
@@ -44,8 +44,7 @@ enum lcfg_status rahunas_visitor(const char *key, void *data, size_t size,
 
   if (strncmp(main_key, "main", 4) == 0) {
     cfg_type = MAIN;
-
-  } if (strncmp(main_key, "service_class", strlen ("service_class")) == 0) {
+  } else if (strncmp(main_key, "service_class", strlen ("service_class")) == 0) {
     cfg_type = SERVICECLASS;
   } else {
     cfg_type = VSERVER;
@@ -59,6 +58,10 @@ enum lcfg_status rahunas_visitor(const char *key, void *data, size_t size,
         if (config->rh_main.conf_dir != NULL)
           free(config->rh_main.conf_dir);
         config->rh_main.conf_dir = strdup(value);
+      } else if (strncmp(sub_key, "serviceclass_conf_dir", 21) == 0) {
+        if (config->rh_main.serviceclass_conf_dir != NULL)
+          free(config->rh_main.serviceclass_conf_dir);
+        config->rh_main.serviceclass_conf_dir = strdup(value);
       } else if (strncmp(sub_key, "log_file", 8) == 0) {
         if (config->rh_main.log_file != NULL)
           free(config->rh_main.log_file);
@@ -67,11 +70,10 @@ enum lcfg_status rahunas_visitor(const char *key, void *data, size_t size,
         if (config->rh_main.dhcp != NULL)
           free(config->rh_main.dhcp);
         config->rh_main.dhcp = strdup(value);
+      } else if (strncmp(sub_key, "serviceclass", 12) == 0) {
+        config->rh_main.serviceclass = strncmp(value, "yes", 3) == 0 ? 1 : 0;
       } else if (strncmp(sub_key, "bandwidth_shape", 15) == 0) {
-        if (strncmp(value, "yes", 3) == 0)
-          config->rh_main.bandwidth_shape = 1; 
-        else
-          config->rh_main.bandwidth_shape = 0;
+        config->rh_main.bandwidth_shape = strncmp(value, "yes", 3) == 0 ? 1 : 0;
       } else if (strncmp(sub_key, "bittorrent_download_max", 23) == 0) {
         config->rh_main.bittorrent_download_max = atoi(value); 
       } else if (strncmp(sub_key, "bittorrent_upload_max", 21) == 0) {
@@ -82,10 +84,13 @@ enum lcfg_status rahunas_visitor(const char *key, void *data, size_t size,
       break;
 
     case SERVICECLASS:
-      if (strncmp (sub_key, "name", strlen("name")) == 0) {
-        if (config->rh_serviceclass.name != NULL)
-          free(config->rh_serviceclass.name);
-        config->rh_serviceclass.name = strdup(value);
+      if (strncmp (sub_key, "serviceclass_id",
+            strlen("serviceclass_id")) == 0) {
+        config->rh_serviceclass.serviceclass_id = atoi (value);
+      } else if (strncmp (sub_key, "serviceclass_name", strlen("serviceclass_name")) == 0) {
+        if (config->rh_serviceclass.serviceclass_name != NULL)
+          free(config->rh_serviceclass.serviceclass_name);
+        config->rh_serviceclass.serviceclass_name = strdup(value);
       } else if (strncmp (sub_key, "description", strlen("description")) == 0) {
         if (config->rh_serviceclass.description != NULL)
           free(config->rh_serviceclass.description);
@@ -113,10 +118,8 @@ enum lcfg_status rahunas_visitor(const char *key, void *data, size_t size,
               }
             else
               {
-                // Start address should not be the network address
-                config->rh_serviceclass.start_addr.s_addr += 1;
                 DP ("service_class: %s - start ip = %s, size: %d",
-                    config->rh_serviceclass.name,
+                    config->rh_serviceclass.serviceclass_name,
                     inet_ntoa (config->rh_serviceclass.start_addr),
                     config->rh_serviceclass.network_size);
               }
@@ -129,24 +132,24 @@ enum lcfg_status rahunas_visitor(const char *key, void *data, size_t size,
         }
 
         if (!valid) {
-          if (config->rh_serviceclass.name != NULL) {
+          if (config->rh_serviceclass.serviceclass_name != NULL) {
             syslog(LOG_ERR, "\"%s\" service_class config config error: "
                             "invalid network %s",
-                            config->rh_serviceclass.name, value);
+                            config->rh_serviceclass.serviceclass_name, value);
           } else {
             syslog(LOG_ERR, "unknown service_class config error: "
                             "invalid network %s", value);
           }
         }
-      } else if (strncmp (sub_key, "fake_arpd", strlen("fake_arpd")) == 0) {
-        if (config->rh_serviceclass.fake_arpd != NULL)
-          free(config->rh_serviceclass.fake_arpd);
-        config->rh_serviceclass.fake_arpd = strdup(value);
       } else if (strncmp (sub_key, "fake_arpd_iface",
                  strlen("fake_arpd_iface")) == 0) {
         if (config->rh_serviceclass.fake_arpd_iface != NULL)
           free(config->rh_serviceclass.fake_arpd_iface);
         config->rh_serviceclass.fake_arpd_iface = strdup(value);
+      } else if (strncmp (sub_key, "fake_arpd", strlen("fake_arpd")) == 0) {
+        if (config->rh_serviceclass.fake_arpd != NULL)
+          free(config->rh_serviceclass.fake_arpd);
+        config->rh_serviceclass.fake_arpd = strdup(value);
       }
       break;
 
@@ -373,6 +376,35 @@ int get_vservers_config(const char *conf_dir, struct main_server *server)
   return 0;
 }
 
+int get_serviceclass_config(const char *conf_dir, struct main_server *server)
+{
+  DIR *dp;
+  struct dirent *dirp;
+  void *data = NULL;
+  size_t len;
+  char conf_file[200];
+
+  if ((dp = opendir(conf_dir)) == NULL)
+    return errno;
+
+  while ((dirp = readdir(dp)) != NULL) {
+    if (strstr(dirp->d_name, ".conf") == NULL)
+      continue;
+
+    memset(conf_file, 0, sizeof(conf_file));
+
+    strncat(conf_file, conf_dir, sizeof(conf_file));
+    strncat(conf_file, "/", 1);
+    strncat(conf_file, dirp->d_name, sizeof(conf_file));
+
+    syslog(LOG_INFO, "Loading service class config file: %s", conf_file);
+
+    register_serviceclass(server, conf_file);
+  }
+
+  closedir(dp);
+  return 0;
+}
 
 int cleanup_vserver_config(struct rahunas_vserver_config *config)
 {
@@ -415,7 +447,7 @@ int cleanup_vserver_config(struct rahunas_vserver_config *config)
 
 int cleanup_serviceclass_config(struct rahunas_serviceclass_config *config)
 {
-  rh_free(&(config->name));
+  rh_free(&(config->serviceclass_name));
   rh_free(&(config->description));
   rh_free(&(config->network));
   rh_free(&(config->fake_arpd));
@@ -427,6 +459,7 @@ int cleanup_serviceclass_config(struct rahunas_serviceclass_config *config)
 int cleanup_mainserver_config(struct rahunas_main_config *config)
 {
   rh_free(&(config->conf_dir));  
+  rh_free(&(config->serviceclass_conf_dir));
   rh_free(&(config->log_file));
   rh_free(&(config->dhcp));
 
index fe1bd06..a885405 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "../lcfg/lcfg_static.h"
 #include "rh-server.h"
+#include "rh-serviceclass.h"
 
 #define DEFAULT_LOG RAHUNAS_LOG_DIR "rahunas.log"
 #define VSERVER_ID 99
@@ -34,13 +35,14 @@ struct interfaces {
 
 struct rahunas_main_config {
   char *conf_dir;
+  char *serviceclass_conf_dir;
   char *log_file;
   char *dhcp;
+  int  serviceclass;
   int  bandwidth_shape;
   int  bittorrent_download_max;
   int  bittorrent_upload_max;
   int  polling_interval;
-  int  service_class_enabled;
 };
 
 struct rahunas_vserver_config {
@@ -84,7 +86,9 @@ struct rahunas_vserver_config {
 };
 
 struct rahunas_serviceclass_config {
-  char *name;
+  char *serviceclass_name;
+  int  serviceclass_id;
+  int  init_flag;
   char *description;
   char *network;
   struct in_addr start_addr;
@@ -113,11 +117,20 @@ enum vserver_config_init_flag {
   VS_DONE
 };
 
+enum serviceclass_config_init_flag {
+  SC_NONE,
+  SC_INIT,
+  SC_RELOAD,
+  SC_RESET,
+  SC_DONE
+};
+
 extern GList *interfaces_list;
 
 int get_config(const char *cfg_file, union rahunas_config *config);
 int get_value(const char *cfg_file, const char *key, void **data, size_t *len);
 int get_vservers_config(const char *conf_dir, struct main_server *server);
+int get_serviceclass_config(const char *conf_dir, struct main_server *server);
 int cleanup_vserver_config(struct rahunas_vserver_config *config);
 int cleanup_serviceclass_config(struct rahunas_serviceclass_config *config);
 int cleanup_mainserver_config(struct rahunas_main_config *config);
index c377dbb..6c4fd9e 100644 (file)
@@ -9,6 +9,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <syslog.h>
+#include <ipset/ip_set_rahunas_ipiphash.h>
 #include "rh-ipset.h"
 #include "rh-utils.h"
 
@@ -296,6 +297,76 @@ int set_adtip_nb(struct set *rahunas_set, ip_set_ip_t *adtip,
   return res;
 }
 
+int set_ipiphash_adtip(struct set *rahunas_set, const char *ip,
+                       const char *ip1, unsigned op)
+{
+  ip_set_ip_t _ip;
+  ip_set_ip_t _ip1;
+  parse_ip(ip, &_ip);
+  parse_ip(ip1, &_ip1);
+
+  return set_adtip_nb(rahunas_set, &_ip, &_ip1, op);
+}
+
+int set_ipiphash_adtip_nb(struct set *rahunas_set, ip_set_ip_t *ip,
+                          ip_set_ip_t *ip1, unsigned op)
+{
+  struct ip_set_req_adt *req_adt = NULL;
+  struct ip_set_req_rahunas_ipiphash req;
+
+  size_t size;
+  void *data;
+  int res = 0;
+
+  check_protocolversion ();
+
+  if (rahunas_set == NULL)
+    return -1;
+
+  size = ALIGNED(sizeof(struct ip_set_req_adt)) + sizeof(struct ip_set_req_rahunas_ipiphash);
+  data = rh_malloc(size);
+
+  memcpy(&req.ip, ip, sizeof(ip_set_ip_t));
+  memcpy(&req.ip1, ip1, sizeof(ip_set_ip_t));
+
+  req_adt = (struct ip_set_req_adt *) data;
+  req_adt->op = op;
+  req_adt->index = rahunas_set->index;
+  memcpy(data + ALIGNED(sizeof(struct ip_set_req_adt)), &req,
+           sizeof(struct ip_set_req_rahunas_ipiphash));
+
+  if (kernel_sendto_handleerrno(op, data, size) == -1)
+    switch (op) {
+    case IP_SET_OP_ADD_IP:
+      DP("%s:%s is already in set", ip_tostring(ip), ip_tostring(ip1));
+      res = RH_IS_IN_SET;
+      break;
+    case IP_SET_OP_DEL_IP:
+      DP("%s:%s is not in set", ip_tostring(ip), ip_tostring(ip1));
+      res = RH_IS_NOT_IN_SET;
+      break;
+    case IP_SET_OP_TEST_IP:
+      DP("%s:%s is in set", ip_tostring(ip), ip_tostring(ip1));
+      res = RH_IS_IN_SET;
+      break;
+    default:
+      break;
+    }
+  else
+    switch (op) {
+    case IP_SET_OP_TEST_IP:
+      DP("%s:%s is not in set", ip_tostring(ip), ip_tostring(ip1));
+      res = RH_IS_NOT_IN_SET;
+      break;
+    default:
+      break;
+    }
+
+  rh_free(&data);
+
+  return res;
+}
+
 void set_flush(const char *name)
 {
   struct ip_set_req_std req;
index f45d0b7..334531a 100644 (file)
@@ -82,7 +82,12 @@ int set_adtip(struct set *rahunas_set, const char *adtip, const char *adtmac,
               unsigned op);
 
 int set_adtip_nb(struct set *rahunas_set, ip_set_ip_t *adtip, 
-                     unsigned char adtmac[ETH_ALEN], unsigned op);
+                 unsigned char adtmac[ETH_ALEN], unsigned op);
+
+int set_ipiphash_adtip(struct set *rahunas_set, const char *ip,
+                       const char *ip1, unsigned op);
+int set_ipiphash_adtip_nb(struct set *rahunas_set, ip_set_ip_t *ip,
+                          ip_set_ip_t *ip1, unsigned op);
 
 void set_flush(const char *name);
 
index dea93ea..3a0a92b 100644 (file)
@@ -175,6 +175,7 @@ int register_vserver(struct main_server *ms, const char *vserver_cfg_file)
 
   new_vserver->vserver_config = vserver_config;
 
+  new_vserver->main_server = ms;
   new_vserver->vserver_config->init_flag = VS_INIT;
   ms->vserver_list = g_list_append(ms->vserver_list, new_vserver);
   return 0; 
index af86e2d..71d4848 100644 (file)
@@ -9,21 +9,23 @@
 #include <glib.h>
 #include "rh-config.h"
 
-struct vserver {
-  struct rahunas_vserver_config *vserver_config;
-  struct rahunas_vserver_config *dummy_config;
-  struct rahunas_map *v_map;
-  struct set *v_set;
-};
-
 struct main_server {
   struct rahunas_main_config *main_config;
   GList *vserver_list;
+  GList *serviceclass_list;
   GList *task_list;
   int log_fd;
   int polling_blocked;
 };
 
+struct vserver {
+  struct rahunas_vserver_config *vserver_config;
+  struct rahunas_vserver_config *dummy_config;
+  struct rahunas_map *v_map;
+  struct set *v_set;
+  struct main_server *main_server;
+};
+
 struct vserver *vserver_exists(GList *vserver_list, int vserver_id, 
                    const char *vserver_name);
 struct vserver *vserver_get_by_id(struct main_server *ms, int search_id);
diff --git a/src/rh-serviceclass.c b/src/rh-serviceclass.c
new file mode 100644 (file)
index 0000000..4383a27
--- /dev/null
@@ -0,0 +1,310 @@
+/**
+ * RahuNAS service class
+ * Author: Neutron Soutmun <neo.neutron@gmail.com>
+ * Date:   2009-03-24
+ */
+#include <stdio.h>
+#include <arpa/inet.h>
+#include "rahunasd.h"
+#include "rh-serviceclass.h"
+#include "rh-utils.h"
+#include "rh-ipset.h"
+
+int serviceclass_do_init (struct main_server *ms, struct serviceclass *sc);
+
+struct serviceclass *serviceclass_exists(GList *serviceclass_list,
+                                         int serviceclass_id,
+                                         const char *serviceclass_name)
+{
+  GList *runner = g_list_first(serviceclass_list);
+  struct serviceclass *lserviceclass = NULL;
+
+  while (runner != NULL) {
+    lserviceclass = (struct serviceclass *)runner->data;
+
+    if (lserviceclass->serviceclass_config->serviceclass_id == serviceclass_id)
+      return lserviceclass;
+
+    if (strcmp(lserviceclass->serviceclass_config->serviceclass_name,
+        serviceclass_name) == 0)
+      return lserviceclass;
+
+    runner = g_list_next(runner);
+  }
+  return NULL;
+}
+
+struct servicclass *serviceclass_get_by_id(struct main_server *ms,
+                                           int search_id)
+{
+  GList *runner = g_list_first(ms->serviceclass_list);
+  struct serviceclass *lserviceclass = NULL;
+
+  while (runner != NULL) {
+    lserviceclass = (struct serviceclass *)runner->data;
+
+    if (lserviceclass->serviceclass_config->serviceclass_id == search_id) {
+      return lserviceclass;
+    }
+
+    runner = g_list_next(runner);
+  }
+  return NULL;
+}
+
+int serviceclass_cleanup(struct serviceclass *sc)
+{
+  if (sc == NULL)
+    return 0;
+
+  if (sc->serviceclass_config != NULL)
+    cleanup_serviceclass_config(sc->serviceclass_config);
+
+  return 0;
+}
+
+int register_serviceclass(struct main_server *ms,
+                          const char *serviceclass_cfg_file)
+{
+  GList *serviceclass_list = ms->serviceclass_list;
+  GList *chk = NULL;
+  GList *node = NULL;
+  FILE  *cfg_file = NULL;
+  union rahunas_config *cfg_get = NULL;
+  struct rahunas_serviceclass_config *serviceclass_config = NULL;
+  struct serviceclass *new_serviceclass = NULL;
+  struct serviceclass *old_serviceclass = NULL;
+
+  union rahunas_config config = {
+    .rh_serviceclass.serviceclass_name = NULL,
+    .rh_serviceclass.serviceclass_id = 1,
+    .rh_serviceclass.description  = NULL,
+    .rh_serviceclass.network      = NULL,
+    .rh_serviceclass.network_size = 0,
+    .rh_serviceclass.fake_arpd    = NULL,
+    .rh_serviceclass.fake_arpd_iface = NULL,
+    .rh_serviceclass.init_flag    = 0
+  };
+
+  cfg_file = fopen(serviceclass_cfg_file, "r");
+  if (cfg_file == NULL)
+    return -1;
+
+  if (get_config(serviceclass_cfg_file, &config) == 0) {
+    old_serviceclass = serviceclass_exists(serviceclass_list,
+                                      config.rh_serviceclass.serviceclass_id,
+                                      config.rh_serviceclass.serviceclass_name);
+
+    if (old_serviceclass != NULL) {
+      if (old_serviceclass->dummy_config != NULL) {
+        DP("Cleanup old dummy config");
+        rh_free(&old_serviceclass->dummy_config);
+      }
+
+      old_serviceclass->dummy_config =
+        (struct rahunas_serviceclass_config *) rh_malloc(sizeof(struct rahunas_serviceclass_config));
+
+      if (old_serviceclass->dummy_config == NULL)
+        return -1;
+
+      memset(old_serviceclass->dummy_config, 0,
+        sizeof(struct rahunas_serviceclass_config));
+      memcpy(old_serviceclass->dummy_config, &config,
+        sizeof(struct rahunas_serviceclass_config));
+
+      if (strncmp(config.rh_serviceclass.serviceclass_name,
+           old_serviceclass->serviceclass_config->serviceclass_name, 32) != 0) {
+        old_serviceclass->serviceclass_config->init_flag = VS_RESET;
+      } else {
+        old_serviceclass->serviceclass_config->init_flag = VS_RELOAD;
+      }
+      return 1;
+    }
+  } else {
+    return -1;
+  }
+
+  serviceclass_config = (struct rahunas_serviceclass_config *) rh_malloc(sizeof(struct rahunas_serviceclass_config));
+
+  if (serviceclass_config == NULL)
+    return -1;
+
+  memset(serviceclass_config, 0, sizeof(struct rahunas_serviceclass_config));
+
+  memcpy(serviceclass_config, &config, sizeof(struct rahunas_serviceclass_config));
+
+  new_serviceclass = (struct serviceclass *) rh_malloc(sizeof(struct serviceclass));
+
+  if (new_serviceclass == NULL)
+    return -1;
+
+  memset(new_serviceclass, 0, sizeof(struct serviceclass));
+
+  new_serviceclass->serviceclass_config = serviceclass_config;
+
+  new_serviceclass->serviceclass_config->init_flag = VS_INIT;
+  ms->serviceclass_list = g_list_append(ms->serviceclass_list, new_serviceclass);
+  return 0;
+}
+
+int unregister_serviceclass(struct main_server *ms, int serviceclass_id)
+{
+  GList *serviceclass_list = ms->serviceclass_list;
+  GList *runner = g_list_first(serviceclass_list);
+  struct serviceclass *lserviceclass = NULL;
+
+  while (runner != NULL) {
+    lserviceclass = (struct serviceclass *)runner->data;
+    if (lserviceclass->serviceclass_config->serviceclass_id == serviceclass_id) {
+      serviceclass_cleanup(lserviceclass);
+
+      ms->serviceclass_list = g_list_delete_link(ms->serviceclass_list, runner);
+      break;
+    } else {
+      runner = g_list_next(runner);
+    }
+  }
+  return 0;
+}
+
+int unregister_serviceclass_all(struct main_server *ms)
+{
+  GList *serviceclass_list = ms->serviceclass_list;
+  GList *runner = g_list_first(serviceclass_list);
+  GList *deleting = NULL;
+  struct serviceclass *lserviceclass = NULL;
+
+  while (runner != NULL) {
+    lserviceclass = (struct serviceclass *)runner->data;
+    serviceclass_cleanup(lserviceclass);
+    deleting = runner;
+    runner = g_list_next(runner);
+
+    cleanup_serviceclass_config(lserviceclass->serviceclass_config);
+    ms->serviceclass_list = g_list_delete_link(ms->serviceclass_list, deleting);
+  }
+
+  return 0;
+}
+
+int walk_through_serviceclass(int (*callback)(void *, void *), struct main_server *ms)
+{
+  GList *serviceclass_list = ms->serviceclass_list;
+  GList *runner = g_list_first(serviceclass_list);
+  struct serviceclass *sc = NULL;
+
+  while (runner != NULL) {
+    sc = (struct serviceclass *)runner->data;
+
+    (*callback)(ms, sc);
+
+    runner = g_list_next(runner);
+  }
+
+  return 0;
+}
+
+void serviceclass_init(struct main_server *ms, struct serviceclass *sc)
+{
+  struct rahunas_serviceclass_config *sc_config = NULL;
+
+  if (ms == NULL || sc == NULL)
+    return;
+
+  sc_config = sc->serviceclass_config;
+  logmsg (RH_LOG_NORMAL, "[%s] Service class init", sc_config->serviceclass_name);
+
+  serviceclass_do_init (ms, sc);
+
+  sc_config->init_flag = SC_DONE;
+  DP("Service Class (%s) - Configured", sc->serviceclass_config->serviceclass_name);
+}
+
+void serviceclass_reload(struct main_server *ms, struct serviceclass *sc)
+{
+  if (sc->serviceclass_config->init_flag == SC_DONE) {
+    sc->serviceclass_config->init_flag = SC_NONE;
+    return;
+  }
+
+  while (sc->serviceclass_config->init_flag != SC_DONE) {
+    if (sc->serviceclass_config->init_flag == SC_INIT) {
+      logmsg(RH_LOG_NORMAL, "[%s] - Service class config init",
+             sc->serviceclass_config->serviceclass_name);
+
+      serviceclass_do_init (ms, sc);
+
+      sc->serviceclass_config->init_flag = SC_DONE;
+    } else if (sc->serviceclass_config->init_flag == SC_RELOAD) {
+      logmsg(RH_LOG_NORMAL, "[%s] - Service class config reload",
+             sc->serviceclass_config->serviceclass_name);
+
+      if (sc->dummy_config != NULL) {
+        cleanup_serviceclass_config(sc->serviceclass_config);
+        memcpy(sc->serviceclass_config, sc->dummy_config,
+          sizeof(struct rahunas_serviceclass_config));
+      }
+
+      serviceclass_do_init (ms, sc);
+
+      sc->serviceclass_config->init_flag = SC_DONE;
+    } else if (sc->serviceclass_config->init_flag == SC_RESET) {
+      logmsg(RH_LOG_NORMAL, "[%s] - Service class config reset",
+             sc->serviceclass_config->serviceclass_name);
+
+      if (sc->dummy_config != NULL) {
+        cleanup_serviceclass_config(sc->serviceclass_config);
+        memcpy(sc->serviceclass_config, sc->dummy_config,
+          sizeof(struct rahunas_serviceclass_config));
+        rh_free(&sc->dummy_config);
+      }
+
+      sc->serviceclass_config->init_flag = SC_INIT;
+    } else {
+      /* Prevent infinite loop */
+      sc->serviceclass_config->init_flag = SC_DONE;
+    }
+  }
+}
+
+
+void serviceclass_unused_cleanup(struct main_server *ms)
+{
+  GList *serviceclass_list = ms->serviceclass_list;
+  GList *runner = g_list_first(serviceclass_list);
+  struct serviceclass *lserviceclass = NULL;
+
+  while (runner != NULL) {
+    lserviceclass = (struct serviceclass *)runner->data;
+    if (lserviceclass->serviceclass_config->init_flag == SC_NONE) {
+      logmsg(RH_LOG_NORMAL, "[%s] - Service class config removed",
+             lserviceclass->serviceclass_config->serviceclass_name);
+      unregister_serviceclass(ms, lserviceclass->serviceclass_config->serviceclass_id);
+
+      // Set runner to the first of list due to unregister may delete head
+      runner = g_list_first(ms->serviceclass_list);
+    } else {
+      runner = g_list_next(runner);
+    }
+  }
+}
+
+int serviceclass_do_init (struct main_server *ms, struct serviceclass *sc)
+{
+  struct rahunas_serviceclass_config *sc_config = sc->serviceclass_config;
+
+  logmsg (RH_LOG_NORMAL, "[%s] Mapping network: %s",
+                         sc_config->serviceclass_name,
+                         sc_config->network);
+  if (sc_config->fake_arpd != NULL) {
+    if ((strncasecmp (sc_config->fake_arpd, "yes", strlen ("yes")) == 0) &&
+        (sc_config->fake_arpd_iface != NULL)) {
+      logmsg(RH_LOG_NORMAL, "[%s] Fake-arpd: Enabled (on %s)",
+                            sc_config->serviceclass_name,
+                            sc_config->fake_arpd_iface);
+    } else {
+      logmsg(RH_LOG_NORMAL, "[%s] Fake-arpd: Disabled",
+                            sc_config->serviceclass_name);
+    }
+  }
+}
diff --git a/src/rh-serviceclass.h b/src/rh-serviceclass.h
new file mode 100644 (file)
index 0000000..9b527c2
--- /dev/null
@@ -0,0 +1,37 @@
+/**
+ * RahuNAS service class
+ * Author: Neutron Soutmun <neo.neutron@gmail.com>
+ * Date:   2010-07-04
+ */
+#ifndef __RH_SERVICECLASS_H
+#define __RH_SERVICECLASS_H
+
+#include <glib.h>
+#include "rh-config.h"
+
+#define SERVICECLASS_SET_NAME   "rahunas_serviceclass"
+
+struct serviceclass {
+  struct rahunas_serviceclass_config *serviceclass_config;
+  struct rahunas_serviceclass_config *dummy_config;
+};
+
+
+struct serviceclass *serviceclass_exists(GList *serviceclass_list,
+                                         int serviceclass_id,
+                                         const char *servicclass_name);
+
+struct servicclass *serviceclass_get_by_id(struct main_server *ms,
+                                           int search_id);
+int serviceclass_cleanup(struct serviceclass *sc);
+
+int register_serviceclass(struct main_server *ms,
+                          const char *serviceclass_cfg_file);
+int unregister_serviceclass(struct main_server *ms, int serviceclass_id);
+int unregister_serviceclass_all(struct main_server *ms);
+
+void serviceclass_init(struct main_server *ms, struct serviceclass *sc);
+void serviceclass_reload(struct main_server *ms, struct serviceclass *sc);
+void serviceclass_unused_cleanup(struct main_server *ms);
+
+#endif // __RH_SERVICECLASS_H
index 40611ef..53dff32 100644 (file)
@@ -25,6 +25,8 @@ struct dbset_row {
   unsigned short bandwidth_slot_id; 
   long bandwidth_max_down;
   long bandwidth_max_up;
+  gchar *service_class;
+  uint32_t service_class_slot_id;
 };
 
 gboolean get_errors (GdaConnection * connection)
@@ -100,6 +102,12 @@ gboolean *parse_dm_to_struct(GList **data_list, GdaDataModel *dm) {
         row->bandwidth_max_down = atol(str);
       } else if (strncmp("bandwidth_max_up", title, 18) == 0) {
         row->bandwidth_max_up = atol(str);
+      } else if (strncmp("service_class_slot_id", title,
+                         strlen("service_class_slot_id")) == 0) {
+          row->service_class_slot_id = atol(str);
+      } else if (strncmp("service_class", title,
+                         strlen("service_class")) == 0) {
+          row->service_class = g_strdup(str);
       }
     }
   }
@@ -186,6 +194,7 @@ void free_data_list(GList *data_list)
     g_free(row->username);
     g_free(row->ip);
     g_free(row->mac);
+    g_free(row->service_class);
   }
   
   g_list_free (data_list);  
@@ -234,6 +243,9 @@ gboolean restore_set(GList **data_list, struct vserver *vs)
     req.bandwidth_max_down = row->bandwidth_max_down; 
     req.bandwidth_max_up = row->bandwidth_max_up;
 
+    req.serviceclass_name = row->service_class;
+    req.serviceclass_slot_id = row->service_class_slot_id;
+
     rh_task_startsess(vs, &req);
   }
   return TRUE;
@@ -353,8 +365,8 @@ static int startsess (struct vserver *vs, struct task_req *req)
   snprintf(startsess_cmd, sizeof (startsess_cmd), "INSERT INTO dbset"
          "(session_id,vserver_id,username,ip,mac,session_start,"
          "session_timeout,bandwidth_slot_id,bandwidth_max_down,"
-         "bandwidth_max_up) "
-         "VALUES('%s','%d','%s','%s','%s',%s,%s,%u,%lu,%lu)",
+         "bandwidth_max_up,service_class,service_class_slot_id) "
+         "VALUES('%s','%d','%s','%s','%s',%s,%s,%u,%lu,%lu,'%s',%lu)",
          req->session_id, 
          vs->vserver_config->vserver_id, 
          req->username, 
@@ -364,7 +376,9 @@ static int startsess (struct vserver *vs, struct task_req *req)
          time_str2,
          member->bandwidth_slot_id, 
          req->bandwidth_max_down,
-         req->bandwidth_max_up);
+         req->bandwidth_max_up,
+         member->serviceclass_name,
+         member->serviceclass_slot_id);
 
   DP("SQL: %s", startsess_cmd);
 
index 92bf76a..1579592 100644 (file)
@@ -148,6 +148,12 @@ static int startsess (struct vserver *vs, struct task_req *req)
   if (member->session_id && member->username != termstring)
     free(member->session_id);
 
+  if (member->serviceclass_name && member->serviceclass_name != termstring)
+    free(member->serviceclass_name);
+
+  if (member->mapping_ip && member->mapping_ip != termstring)
+    free(member->mapping_ip);
+
   member->username   = strdup(req->username);
   if (!member->username)
     member->username = termstring;
@@ -156,6 +162,10 @@ static int startsess (struct vserver *vs, struct task_req *req)
   if (!member->session_id)
     member->session_id = termstring;
 
+  member->serviceclass_name    = NULL;
+  member->serviceclass_slot_id = 0;
+  member->mapping_ip = termstring;
+
   if (req->session_start == 0) {
     time(&(req->session_start));
   } 
diff --git a/src/rh-task-serviceclass.c b/src/rh-task-serviceclass.c
new file mode 100644 (file)
index 0000000..49fedb2
--- /dev/null
@@ -0,0 +1,300 @@
+/**
+ * RahuNAS task serviceclass implementation 
+ * Author: Neutron Soutmun <neo.neutron@gmail.com>
+ * Date:   2010-07-29
+ */
+
+#include <syslog.h>
+#include <libgda/libgda.h>
+
+#include "rahunasd.h"
+#include "rh-serviceclass.h"
+#include "rh-ipset.h"
+#include "rh-task.h"
+
+static struct set *rh_serviceclass_set = NULL;
+
+static uint32_t _sc_get_slot_id(struct rahunas_serviceclass_config *sc_config)
+{
+  uint32_t slot_id = 0;
+  time_t random_time; 
+  int  retry = 30;
+  char select_cmd[256];
+  GdaConnection *connection = NULL;
+  GdaSqlParser  *parser = NULL;
+  GList *data_list = NULL;
+
+  if (sc_config == NULL)
+    return 0;
+
+  connection = gda_connection_open_from_dsn (PROGRAM, NULL,
+                 GDA_CONNECTION_OPTIONS_READ_ONLY, NULL);
+  parser = gda_connection_create_parser (connection);
+  if (!parser) {
+    parser = gda_sql_parser_new ();
+  }
+
+  g_object_set_data_full (G_OBJECT (connection), "parser", parser, g_object_unref);
+
+  while (slot_id == 0 && (--retry > 0)) {
+    time(&random_time);
+    srandom(random_time);
+    slot_id = random() % sc_config->network_size;
+
+    if (slot_id != 0) {
+      memset (&select_cmd, '\0', sizeof (select_cmd));
+      snprintf(select_cmd, sizeof (select_cmd) - 1,
+               "SELECT * FROM dbset WHERE service_class = '%s' "
+               "AND service_class_slot_id = %u",
+               sc_config->serviceclass_name, slot_id);
+
+      DP("SQL: %s", select_cmd);
+      data_list = execute_sql_command(connection, select_cmd);
+
+      if (g_list_first (data_list) == NULL) {
+        // Available
+        free_data_list(data_list);
+        break;
+      } else { 
+        // Not available, retry
+        free_data_list(data_list);
+        slot_id = 0;
+      }
+    }
+  }
+
+  if (connection)
+    g_object_unref(G_OBJECT(connection));
+
+  return slot_id;
+}
+
+/* Start service task */
+static int startservice ()
+{
+  rh_serviceclass_set = set_adt_get(SERVICECLASS_SET_NAME);
+
+  logmsg(RH_LOG_NORMAL, "Service Class: Flushing set ...");
+  set_flush (SERVICECLASS_SET_NAME);
+  return 0;
+}
+
+/* Stop service task */
+static int stopservice  ()
+{
+  if (rh_serviceclass_set != NULL) {
+    logmsg(RH_LOG_NORMAL, "Service Class: Flushing set ...");
+    set_flush (SERVICECLASS_SET_NAME);
+    rh_free(&rh_serviceclass_set); 
+  }
+
+  return 0;
+}
+
+/* Initialize */
+static void init (struct vserver *vs)
+{
+}
+
+/* Cleanup */
+static void cleanup (struct vserver *vs)
+{
+}
+
+/* Start session task */
+static int startsess (struct vserver *vs, struct task_req *req)
+{
+  struct serviceclass *sc = NULL;
+  struct rahunas_serviceclass_config *sc_config = NULL;
+  ip_set_ip_t ip;
+  ip_set_ip_t ip1;
+  int res = 0;
+  GList *member_node = NULL;
+  struct rahunas_member *member = NULL;
+
+  if (req->serviceclass_name == NULL)
+    return 0;
+
+  member_node = member_get_node_by_id(vs, req->id);
+  if (member_node == NULL)
+    return (-1);
+
+  member = (struct rahunas_member *) member_node->data;
+
+
+  sc = serviceclass_exists(vs->main_server->serviceclass_list, -1,
+                           req->serviceclass_name);
+
+  if (sc == NULL) {
+    goto failed;
+  }
+
+  sc_config = sc->serviceclass_config;
+
+  if (req->serviceclass_slot_id == 0) {
+    req->serviceclass_slot_id = _sc_get_slot_id (sc_config);
+
+    if (req->serviceclass_slot_id == 0)
+      goto failed;
+  }
+
+  if (req->serviceclass_slot_id <= sc_config->network_size) {
+    parse_ip(idtoip(vs->v_map, req->id), &ip);
+    ip1 = ntohl (sc_config->start_addr.s_addr) + req->serviceclass_slot_id;
+
+    res = set_ipiphash_adtip_nb(rh_serviceclass_set, &ip, &ip1, IP_SET_OP_ADD_IP);
+
+    if (res != 0)
+      goto failed;
+
+    res = set_ipiphash_adtip_nb(rh_serviceclass_set, &ip1, &ip, IP_SET_OP_ADD_IP);
+
+    if (res != 0) {
+      // Revert
+      res = set_ipiphash_adtip_nb(rh_serviceclass_set, &ip, &ip1, IP_SET_OP_DEL_IP);
+      goto failed;
+    }
+
+
+    member->serviceclass_name = strdup (req->serviceclass_name);
+    member->serviceclass_slot_id = req->serviceclass_slot_id;
+
+    member->mapping_ip = strdup (ip_tostring(ip1));
+
+    logmsg (RH_LOG_NORMAL, "[%s] Service class for User: %s, IP: %s "
+                           "- Service Class: %s, Mapping: %s",
+                           vs->vserver_config->vserver_name,
+                           req->username,
+                           idtoip(vs->v_map, req->id),
+                           req->serviceclass_name,
+                           member->mapping_ip);
+  } else {
+    goto failed;
+  }
+
+  return 0;
+
+failed:
+  logmsg (RH_LOG_NORMAL, "[%s] Service class for User: %s, IP: %s "
+                         "- Service Class: %s, Failed!",
+                         vs->vserver_config->vserver_name,
+                         req->username,
+                         idtoip(vs->v_map, req->id),
+                         req->serviceclass_name);
+
+  return 0;
+}
+
+/* Stop session task */
+static int stopsess  (struct vserver *vs, struct task_req *req)
+{
+  struct serviceclass *sc = NULL;
+  struct rahunas_serviceclass_config *sc_config = NULL;
+  ip_set_ip_t ip;
+  ip_set_ip_t ip1;
+  int res = 0;
+  GList *member_node = NULL;
+  struct rahunas_member *member = NULL;
+
+  if (req->serviceclass_name == NULL)
+    return 0;
+
+  member_node = member_get_node_by_id(vs, req->id);
+  if (member_node == NULL)
+    return (-1);
+
+  member = (struct rahunas_member *) member_node->data;
+
+  sc = serviceclass_exists(vs->main_server->serviceclass_list, -1,
+                           member->serviceclass_name);
+
+  if (sc == NULL) {
+    goto failed;
+  }
+
+  sc_config = sc->serviceclass_config;
+
+  if (member->serviceclass_slot_id == 0) {
+    goto failed;
+  }
+
+  if (member->serviceclass_slot_id <= sc_config->network_size) {
+    parse_ip(idtoip(vs->v_map, req->id), &ip);
+    ip1 = ntohl (sc_config->start_addr.s_addr) + member->serviceclass_slot_id;
+
+    res = set_ipiphash_adtip_nb(rh_serviceclass_set, &ip, &ip1, IP_SET_OP_DEL_IP);
+
+    if (res != 0)
+      goto failed;
+
+    res = set_ipiphash_adtip_nb(rh_serviceclass_set, &ip1, &ip, IP_SET_OP_DEL_IP);
+    if (res != 0)
+      goto failed;
+
+    logmsg (RH_LOG_NORMAL, "[%s] Service class for User: %s, IP: %s "
+                           "- Service Class: %s, Mapping: %s (Removed)",
+                           vs->vserver_config->vserver_name,
+                           member->username,
+                           idtoip(vs->v_map, req->id),
+                           member->serviceclass_name,
+                           member->mapping_ip);
+  } else {
+    goto failed;
+  }
+
+  return 0;
+
+failed:
+  logmsg (RH_LOG_NORMAL, "[%s] Service class for User: %s, IP: %s "
+                         "- Service Class: %s, Mapping: %s (Removed Failed!)",
+                         vs->vserver_config->vserver_name,
+                         member->username,
+                         idtoip(vs->v_map, req->id),
+                         member->serviceclass_name,
+                         member->mapping_ip);
+
+  return 0;
+}
+
+/* Commit start session task */
+static int commitstartsess (struct vserver *vs, struct task_req *req)
+{
+  /* Do nothing or need to implement */
+}
+
+/* Commit stop session task */
+static int commitstopsess  (struct vserver *vs, struct task_req *req)
+{
+  /* Do nothing or need to implement */
+}
+
+/* Rollback start session task */
+static int rollbackstartsess (struct vserver *vs, struct task_req *req)
+{
+  /* Do nothing or need to implement */
+}
+
+/* Rollback stop session task */
+static int rollbackstopsess  (struct vserver *vs, struct task_req *req)
+{
+  /* Do nothing or need to implement */
+}
+
+static struct task task_serviceclass = {
+  .taskname = "SERVICECLASS",
+  .taskprio = 25,
+  .init = &init,
+  .cleanup = &cleanup,
+  .startservice = &startservice,
+  .stopservice = &stopservice,
+  .startsess = &startsess,
+  .stopsess = &stopsess,
+  .commitstartsess = &commitstartsess,
+  .commitstopsess = &commitstopsess,
+  .rollbackstartsess = &rollbackstartsess,
+  .rollbackstopsess = &rollbackstopsess,
+};
+
+void rh_task_serviceclass_reg(struct main_server *ms) {
+  task_register(ms, &task_serviceclass);
+}
diff --git a/src/rh-task-serviceclass.h b/src/rh-task-serviceclass.h
new file mode 100644 (file)
index 0000000..ba40e96
--- /dev/null
@@ -0,0 +1,12 @@
+/**
+ * RahuNAS task serviceclass implementation 
+ * Author: Neutron Soutmun <neo.neutron@gmail.com>
+ * Date:   2010-07-29
+ */
+#ifndef __RH_TASK_SERVICECLASS_H
+#define __RH_TASK_SERVICECLASS_H
+
+extern void rh_task_serviceclass_reg(struct main_server *ms);
+
+#endif // __RH_TASK_SERVICECLASS_H
+
index 37fb06a..90f0c44 100644 (file)
@@ -55,6 +55,9 @@ void rh_task_register(struct main_server *ms)
     rh_task_memset_reg(ms);
     rh_task_ipset_reg(ms);
 
+    if (ms->main_config->serviceclass)
+      rh_task_serviceclass_reg(ms);
+
     if (ms->main_config->bandwidth_shape)
       rh_task_bandwidth_reg(ms);
 
index 78f03eb..38437b0 100644 (file)
@@ -22,6 +22,8 @@ struct task_req {
   unsigned short bandwidth_slot_id; 
   unsigned long bandwidth_max_down;
   unsigned long bandwidth_max_up;
+  const char *serviceclass_name;
+  uint32_t serviceclass_slot_id;
   unsigned short req_opt;
 };
 
index d1947ce..c2dd79a 100644 (file)
@@ -34,7 +34,7 @@ int do_startsession(GNetXmlRpcServer *server,
   gchar *session_timeout = NULL;
   gchar *bandwidth_max_down = NULL;
   gchar *bandwidth_max_up = NULL;
-  gchar *service_class = NULL;
+  gchar *serviceclass_name = NULL;
   gchar *vserver_id = NULL;
   uint32_t id;
   GList *member_node = NULL;
@@ -52,7 +52,7 @@ int do_startsession(GNetXmlRpcServer *server,
   session_timeout    = rh_string_get_sep(param, "|", 5);
   bandwidth_max_down = rh_string_get_sep(param, "|", 6);
   bandwidth_max_up   = rh_string_get_sep(param, "|", 7);
-  service_class      = rh_string_get_sep(param, "|", 8);
+  serviceclass_name  = rh_string_get_sep(param, "|", 8);
   vserver_id         = rh_string_get_sep(param, "|", 9);
 
   if (ip == NULL || username == NULL || session_id == NULL 
@@ -110,9 +110,11 @@ greeting:
   if (member_node != NULL) {
     member = (struct rahunas_member *)member_node->data;
     *reply_string = g_strdup_printf("Greeting! Got: IP %s, User %s, ID %s, "
-                                    "VIP-IP %s",
+                                    "Service Class %s, Mapping %s",
                                     ip, member->username, 
-                                    member->session_id, "");
+                                    member->session_id,
+                                    member->serviceclass_name,
+                                    member->mapping_ip);
     goto cleanup;
   }
 
@@ -129,7 +131,7 @@ cleanup:
   g_free(session_timeout);
   g_free(bandwidth_max_down);
   g_free(bandwidth_max_up);
-  g_free(service_class);
+  g_free(serviceclass_name);
   g_free(vserver_id);
   return 0;
 }
index 6a700c0..0263628 100755 (executable)
@@ -39,7 +39,7 @@ get_config_value () {
   key=$2
   file=$3
 
-  cat $file | sed -e "0,/$section = {/ ! { /}/,/$section = {/ ! s/^/>>/ }" | grep "^>>" | sed -e "s/^>>//g" | grep -w "$key" | cut -d= -f2 | sed "s/^ *\(.*[^ ]\) *$/\1/" | sed 's/"//g'
+  cat $file | sed -e "0,/$section = {/ ! { /}/,/$section = {/ ! s/^/>>/ }" | grep "^>>" | sed -e "s/^>>//g" | grep -w "$key[ ]*=" | cut -d= -f2 | sed "s/^ *\(.*[^ ]\) *$/\1/" | sed 's/"//g'
 }
 
 ##
@@ -48,6 +48,7 @@ get_config_value () {
 
 # Main
 MAIN_CONF_DIR=`get_config_value main conf_dir $RAHUNAS_CONFIG`
+MAIN_SERVICECLASS=`get_config_value main serviceclass $RAHUNAS_CONFIG`
 MAIN_BANDWIDTH_SHAPE=`get_config_value main bandwidth_shape $RAHUNAS_CONFIG`
 MAIN_BITTORRENT_DOWNLOAD_MAX=`get_config_value main bittorrent_download_max $RAHUNAS_CONFIG`
 MAIN_BITTORRENT_UPLOAD_MAX=`get_config_value main bittorrent_upload_max $RAHUNAS_CONFIG`
@@ -78,8 +79,6 @@ if [ "$ENV_OVERRIDE" != "yes" ]; then
   VSERVER_PORTS_ALLOW=
   VSERVER_PORTS_INTERCEPT=
   SETNAME=
-  VIPMAP=
-  VIPMAP_FAKE_ARP=
 fi
 
 DEV_EXTERNAL_LIST=
@@ -100,8 +99,6 @@ CHAIN_MANGLE_POSTROUTING=
 CHAIN_NAT_PREROUTING=
 CHAIN_NAT_POSTROUTING=
 CHAIN_NAT_AUTHEN=
-CHAIN_NAT_VIP_PREROUTING=
-CHAIN_NAT_VIP_POSTROUTING=
 CHAIN_P2P_DETECT=
 CHAIN_P2P_RECHECK=
 CHAIN_P2P_CHECK=
@@ -150,9 +147,6 @@ get_config () {
     BITTORRENT_ALLOW=`get_config_value $SETNAME bittorrent_allow $file`
     VSERVER_PORTS_ALLOW=`get_config_value $SETNAME vserver_ports_allow $file`
     VSERVER_PORTS_INTERCEPT=`get_config_value $SETNAME vserver_ports_intercept $file`
-    VIPMAP=`get_config_value $SETNAME vipmap $file`
-    VIPMAP_NETWORK=`get_config_value $SETNAME vipmap_network $file`
-    VIPMAP_FAKE_ARP=`get_config_value $SETNAME vipmap_fake_arp $file`
   fi
  
   BANDWIDTH_SHAPE=$MAIN_BANDWIDTH_SHAPE
@@ -179,8 +173,6 @@ get_config () {
   CHAIN_NAT_PREROUTING="${SETNAME}_nat_pre"
   CHAIN_NAT_POSTROUTING="${SETNAME}_nat_post"
   CHAIN_NAT_AUTHEN="${SETNAME}_nat_authen"
-  CHAIN_NAT_VIP_PREROUTING="${SETNAME}_nat_vip_pre"
-  CHAIN_NAT_VIP_POSTROUTING="${SETNAME}_nat_vip_post"
   
   # P2P checking chains declaration
   CHAIN_P2P_DETECT="${SETNAME}_p2p_detect"
@@ -229,10 +221,6 @@ add_set () {
   
   $IPSET -N $SETNAME rahunas $ipset_opt $ipset_ignoremac 
 
-  if [ "$VIPMAP" = "yes" ]; then
-    $IPSET -N ${SETNAME}-vip rahunas $ipset_opt $ipset_ignoremac
-  fi
-
   if [ "$BITTORRENT" = "throttle" ]; then
     $IPSET -N $P2P_SET iphash
   fi
@@ -253,11 +241,6 @@ cleanup_set () {
   $IPSET -F $SETNAME
   $IPSET -X $SETNAME
 
-  if [ "$VIPMAP" = "yes" ]; then
-    $IPSET -F ${SETNAME}-vip
-    $IPSET -X ${SETNAME}-vip
-  fi
-
   if [ "$BITTORRENT" = "throttle" ]; then
     $IPSET -F $P2P_SET
     $IPSET -X $P2P_SET 
@@ -373,8 +356,11 @@ navigation_rules () {
       $DEV_OUT_PARAM $dev -s $CLIENTS \
       -j $CHAIN_NAT_POSTROUTING
   done
+
+
 }
 
+
 ##
 # Cleanup old rules
 ##
@@ -412,14 +398,6 @@ cleanup () {
   $IPTABLES -t nat -F $CHAIN_NAT_AUTHEN
   $IPTABLES -t nat -X $CHAIN_NAT_AUTHEN
 
-  if [ "$VIPMAP" = "yes" ]; then
-    $IPTABLES -t nat -F $CHAIN_NAT_VIP_PREROUTING
-    $IPTABLES -t nat -X $CHAIN_NAT_VIP_PREROUTING
-
-    $IPTABLES -t nat -F $CHAIN_NAT_VIP_POSTROUTING
-    $IPTABLES -t nat -X $CHAIN_NAT_VIP_POSTROUTING
-  fi
-
   if [ "$BITTORRENT" = "throttle" ]; then
     $IPTABLES -t mangle -F $CHAIN_P2P_CHECK
     $IPTABLES -t mangle -X $CHAIN_P2P_CHECK
@@ -447,11 +425,6 @@ new_chains () {
   $IPTABLES -t nat -N $CHAIN_NAT_POSTROUTING
   $IPTABLES -t nat -N $CHAIN_NAT_AUTHEN
 
-  if [ "$VIPMAP" = "yes" ]; then
-    $IPTABLES -t nat -N $CHAIN_NAT_VIP_PREROUTING
-    $IPTABLES -t nat -N $CHAIN_NAT_VIP_POSTROUTING
-  fi
-
   if [ "$BITTORRENT" = "throttle" ]; then
     $IPTABLES -t mangle -N $CHAIN_P2P_CHECK
     $IPTABLES -t mangle -N $CHAIN_P2P_RECHECK
@@ -674,22 +647,20 @@ rules () {
       fi
     fi
 
-    if [ "$VIPMAP" = "yes" ]; then
+    if [ "$MAIN_SERVICECLASS" = "yes" ]; then
       $IPTABLES -t nat -A $CHAIN_NAT_PREROUTING \
-        -m set --set ${SETNAME}-vip src -j $CHAIN_NAT_VIP_PREROUTING
-
-      $IPTABLES -t nat -A $CHAIN_NAT_VIP_PREROUTING -j ACCEPT
+        -m set --set rahunas_serviceclass src -j ACCEPT
     fi
 
     if [ "$PROXY" = "transparent" ]; then
       if [ "$PROXY_HOST" = "localhost" ] || [ "$PROXY_HOST" = "127.0.0.1" ]
       then
         $IPTABLES -t nat -A $CHAIN_NAT_PREROUTING -p tcp --dport http \
-          -d ! $VSERVER_IP \
+          ! -d $VSERVER_IP \
           -m connmark --mark 2/2 -j REDIRECT --to-ports $PROXY_PORT
       else
         $IPTABLES -t nat -A $CHAIN_NAT_PREROUTING -p tcp --dport http \
-          -d ! $VSERVER_IP \
+          ! -d $VSERVER_IP \
           -m connmark --mark 2/2 \
           -j DNAT --to-destination $PROXY_HOST:$PROXY_PORT
       fi
@@ -701,7 +672,7 @@ rules () {
   ##
   
   $IPTABLES -t nat -A $CHAIN_NAT_PREROUTING -p tcp -m multiport \
-    --dports $VSERVER_PORTS_INTERCEPT -d ! $VSERVER_IP \
+    --dports $VSERVER_PORTS_INTERCEPT ! -d $VSERVER_IP \
     -m connmark ! --mark 2/2 \
     -j $CHAIN_NAT_AUTHEN
   
@@ -711,11 +682,6 @@ rules () {
   ##
   # MASQUERADE
   ##
-  if [ "$VIPMAP" = "yes" ]; then
-    $IPTABLES -t nat -A $CHAIN_NAT_POSTROUTING \
-      -m set --set ${SETNAME}-vip src -j $CHAIN_NAT_VIP_POSTROUTING
-  fi
-
   if [ "$MASQUERADE" = "yes" ]; then
     $IPTABLES -t nat -A $CHAIN_NAT_POSTROUTING -j MASQUERADE
   fi
@@ -743,16 +709,41 @@ rules () {
   $IPTABLES -t mangle -A $CHAIN_MANGLE_POSTROUTING -j RETURN
   $IPTABLES -t nat -A $CHAIN_NAT_PREROUTING -j RETURN
   $IPTABLES -t nat -A $CHAIN_NAT_POSTROUTING -j RETURN
+}
+
+##
+# Service class set
+##
+serviceclass_set () {
+  opt=$1
+  if [ "$opt" = "start" ]; then
+    $IPSET -N rahunas_serviceclass rahunas_ipiphash
+  elif [ "$opt" = "cleanup" ]; then
+    $IPSET -F rahunas_serviceclass
+    $IPSET -X rahunas_serviceclass
+  fi
+}
+
+##
+# Service class rules
+##
+serviceclass_rules () {
+  opt=$1
+  if [ "$opt" = "start" ]; then
+    action="-I"
+  elif [ "$opt" = "stop" ]; then
+    action="-D"
+  fi
 
-  if [ "$VIPMAP" = "yes" ]; then
-    $IPTABLES -t nat -A $CHAIN_NAT_VIP_PREROUTING -j RETURN
-    $IPTABLES -t nat -A $CHAIN_NAT_VIP_POSTROUTING -j RETURN
+  if [ "$MAIN_SERVICECLASS" = "yes" -o "$opt" = "stop" ]; then
+    # RAW - Service class
+    $IPTABLES -t raw $action PREROUTING \
+      -m set --set rahunas_serviceclass src \
+      -j RAHURAWDNAT --bind-set rahunas_serviceclass
 
-    if [ "$VIPMAP_FAKE_ARP" = "yes" ]; then
-      for dev in $DEV_EXTERNAL_LIST; do
-        $FARPD -i $dev $VIPMAP_NETWORK
-      done
-    fi
+    $IPTABLES -t rawpost $action POSTROUTING \
+      -m set --set rahunas_serviceclass dst \
+      -j RAHURAWSNAT --bind-set rahunas_serviceclass
   fi
 }
 
@@ -789,11 +780,19 @@ start () {
 
   policy 
 
+  if [ "$MAIN_SERVICECLASS" = "yes" ]; then
+    serviceclass_set start
+    serviceclass_rules start
+  fi
+
   touch $RUN
 }
 
 stop () {
   test -f $RUN || return 0
+
+  serviceclass_rules stop
+  serviceclass_set cleanup
    
   cleanup_policy
 
diff --git a/tools/rahunas-vipmap.in b/tools/rahunas-vipmap.in
deleted file mode 100755 (executable)
index 6ea5425..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/bin/sh
-
-PATH=/sbin:/bin:/usr/sbin:/usr/bin:@prefix@/sbin:@prefix@/bin
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-
-IPTABLES=/sbin/iptables
-
-case "$1" in
-  add)
-    $IPTABLES -t nat -I ${2}_nat_vip_post -s ${3} -j SNAT --to-source ${4}
-    if [ $? -eq 0 ]; then
-      echo "Adding VIP map: ${3} => ${4}"
-    fi
-    ;;
-  del)
-    $IPTABLES -t nat -D ${2}_nat_vip_post -s ${3} -j SNAT --to-source ${4}
-    if [ $? -eq 0 ]; then
-      echo "Deleting VIP map: ${3} => ${4}"
-    fi
-    ;;
-  *)
-    N=@sbindir@/rahunas-vipmap
-    echo "Usage: $N {add|del} vserver_name client_ip vipmap_ip"
-    exit 3
-    ;;
-esac 
-
-exit 0
index 4397a5a..1ac7122 100644 (file)
@@ -45,7 +45,6 @@ require_once 'networkchk.php';
 $ip = $_SERVER['REMOTE_ADDR'];
 $config = get_config_by_network($ip, $config_list);
 $vserver_id = $config["VSERVER_ID"];
-$vip_user = 0;
 
 $forward = false;
 $LogoutURL  = $config['NAS_LOGIN_PROTO'] . "://" . $config['NAS_LOGIN_HOST'];
@@ -102,12 +101,6 @@ if (!empty($_POST['user']) && !empty($_POST['passwd'])) {
     $racct->calling_station_id = returnMacAddress();
     $racct->gen_session_id();
 
-    if ($config["VIPMAP"] == "yes" &&
-          !empty ($rauth->attributes[$config["VIPMAP_ATTRIBUTE"]])) {
-      $vip_user = 1;
-    }
-
-
     try {
       $prepareData = array (
         "IP" => $ip,
@@ -117,14 +110,14 @@ if (!empty($_POST['user']) && !empty($_POST['passwd'])) {
         "Session-Timeout" => $rauth->attributes['session_timeout'],
         "Bandwidth-Max-Down" => $rauth->attributes['WISPr-Bandwidth-Max-Down'],
         "Bandwidth-Max-Up" => $rauth->attributes['WISPr-Bandwidth-Max-Up'],
-        "Vip_User" => $vip_user,
+        "Class-Of-Service" => $rauth->attributes['WISPr-Billing-Class-Of-Service'],
       );
       $result = $xmlrpc->do_startsession($vserver_id, $prepareData);
       if (strstr($result,"Client already login")) {
         $message = get_message('ERR_ALREADY_LOGIN');
         $forward = false;
       } else if (strstr($result, "Greeting")) {
-        $split = explode ("VIP-IP ", $result);
+        $split = explode ("Mapping ", $result);
         $called_station_id = $split[1];
         if (!empty ($called_station_id))
           $racct->called_station_id = $called_station_id;