[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
(usagi-users 02931) [patch] configuration support for addrsel policy table in 2.6
- To: usagi-users@xxxxxxxxxxxxxx
- Subject: (usagi-users 02931) [patch] configuration support for addrsel policy table in 2.6
- From: Antonio Tapiador del Dujo <atapiador@xxxxxxxxxx>
- Date: Wed, 21 Apr 2004 11:14:03 +0200
- Mail-followup-to: usagi-users@xxxxxxxxxxxxxx
- Reply-to: usagi-users@xxxxxxxxxxxxxx
- Resent-date: Sat, 24 Apr 2004 02:03:25 +0900
- Resent-from: sekiya@xxxxxxxxxxxxxx
- Resent-message-id: <200404240203.FMLAAB15759.usagi-users@linux-ipv6.org>
- Resent-to: usagi-users@xxxxxxxxxxxxxx (moderated)
- Sender: Antonio Tapiador del Dujo <atd@xxxxxxxxxxxxxxxx>
- User-agent: Mutt/1.5.5.1+cvs20040105i
Hi,
I send again a patch to support address selection Policy table
configuration in 2.6 kernel, as suggested in RFC 3484.
Please, consider applying it.
Thank you.
--
EuropeSwPatentFree - http://EuropeSwPatentFree.hispalinux.es
diff -urN -X ../dontdiff usagi.0412/kernel/linux26/include/linux/in6.h usagi/kernel/linux26/include/linux/in6.h
--- usagi.0412/kernel/linux26/include/linux/in6.h 2004-02-14 03:15:19.000000000 +0100
+++ usagi/kernel/linux26/include/linux/in6.h 2004-04-20 12:28:20.000000000 +0200
@@ -93,6 +93,9 @@
#define IPV6_FL_S_USER 3
#define IPV6_FL_S_ANY 255
+/* device controls */
+#define SIOCSDADDRLABEL (SIOCPROTOPRIVATE + 2)
+#define SIOCDDADDRLABEL (SIOCPROTOPRIVATE + 3)
/*
* Bitmask constant declarations to help applications select out the
diff -urN -X ../dontdiff usagi.0412/kernel/linux26/include/linux/ipv6.h usagi/kernel/linux26/include/linux/ipv6.h
--- usagi.0412/kernel/linux26/include/linux/ipv6.h 2004-03-01 11:51:36.000000000 +0100
+++ usagi/kernel/linux26/include/linux/ipv6.h 2004-04-20 12:28:20.000000000 +0200
@@ -28,6 +28,14 @@
int ifr6_ifindex;
};
+struct in6_addrlabelreq {
+ struct in6_addr addr;
+ __u16 plen;
+ __u16 __reserved;
+ __u32 ifindex;
+ __u32 label;
+};
+
#define IPV6_SRCRT_STRICT 0x01 /* this hop must be a neighbor */
#define IPV6_SRCRT_TYPE_0 0 /* IPv6 type 0 Routing Header */
diff -urN -X ../dontdiff usagi.0412/kernel/linux26/include/net/addrconf.h usagi/kernel/linux26/include/net/addrconf.h
--- usagi.0412/kernel/linux26/include/net/addrconf.h 2004-03-01 11:51:37.000000000 +0100
+++ usagi/kernel/linux26/include/net/addrconf.h 2004-04-20 12:28:20.000000000 +0200
@@ -75,6 +75,7 @@
struct in6_addr *addr);
extern void addrconf_leave_solict(struct net_device *dev,
struct in6_addr *addr);
+extern int addrconf_label_ioctl(unsigned int cmd, void *arg);
/*
* multicast prototypes (mcast.c)
diff -urN -X ../dontdiff usagi.0412/kernel/linux26/net/ipv6/addrconf.c usagi/kernel/linux26/net/ipv6/addrconf.c
--- usagi.0412/kernel/linux26/net/ipv6/addrconf.c 2004-03-20 15:20:27.000000000 +0100
+++ usagi/kernel/linux26/net/ipv6/addrconf.c 2004-04-20 12:28:20.000000000 +0200
@@ -38,6 +38,8 @@
* YOSHIFUJI Hideaki @USAGI : improved source address
* selection; consider scope,
* status etc.
+ * Antonio Tapiador : Label table user level
+ * <atapiador@xxxxxxxxxx> configuration
*/
#include <linux/config.h>
@@ -147,6 +149,18 @@
static u32 ipv6_addrselect_label_lookup(const struct in6_addr *addr, int ifindex);
+struct ipv6_addrselect_label
+{
+ struct ipv6_addrselect_label *next;
+ struct in6_addr addr;
+ u16 plen;
+ u32 ifindex;
+ u32 label;
+};
+
+struct ipv6_addrselect_label *ipv6_addrselect_label_table;
+rwlock_t addrselect_label_lock = RW_LOCK_UNLOCKED;
+
struct ipv6_devconf ipv6_devconf = {
.forwarding = 0,
.hop_limit = IPV6_DEFAULT_HOPLIMIT,
@@ -1054,47 +1068,96 @@
}
/* address selection: default policy label */
-/* XXX: user level configuration */
-static struct ipv6_addrselect_label {
- struct in6_addr addr;
- u16 plen;
- u32 ifindex;
- u32 label;
-} ipv6_addrselect_label_table[] = {
- /* ::1/128, label = 0 */
- {
- .addr = IN6ADDR_LOOPBACK_INIT,
- .plen = 128,
- .label = 0,
- },
- /* ::/0, label = 1 */
- {
- .addr = IN6ADDR_ANY_INIT,
- .plen = 0,
- .label = 1,
- },
- /* 2002::/16, label = 2 */
- {
- .addr = {{{ 0x20, 0x02 }}},
- .plen = 16,
- .label = 2,
- },
- /* ::/96, label = 3 */
- {
- .plen = 96,
- .label = 3,
- },
- /* ::ffff:0:0/96, label = 4 */
- {
- .addr = {{{ [10] = 0xff, [11] = 0xff }}},
- .plen = 96,
- .label = 4,
- },
- /* sentinel */
- {
- .label = 0xffffffff,
+int ipv6_addrselect_add_label(int ifindex, struct in6_addr *addr, int plen, int label)
+{
+ struct ipv6_addrselect_label *p, *p_last;
+
+ /* Update label on duplicate addresses */
+ write_lock_bh(&addrselect_label_lock);
+ p_last = ipv6_addrselect_label_table;
+ for (p = ipv6_addrselect_label_table;
+ p;
+ p = p->next) {
+ if (ipv6_addr_diff(addr, &p->addr) >= plen && plen == p->plen) {
+ p->ifindex = ifindex;
+ p->label = label;
+ write_unlock_bh(&addrselect_label_lock);
+ return 0;
+ }
+ p_last = p;
}
-};
+
+ p = kmalloc(sizeof(struct ipv6_addrselect_label), GFP_KERNEL);
+ if (p == NULL) {
+ ADBG((KERN_WARNING
+ "ipv6_addrselect_add_label: malloc failed\n"));
+ write_unlock_bh(&addrselect_label_lock);
+ return -ENOMEM;
+ }
+
+ memset(p, 0, sizeof(struct ipv6_addrselect_label));
+
+ if (!ipv6_addrselect_label_table)
+ ipv6_addrselect_label_table = p;
+ else
+ p_last->next = p;
+ p->addr = *addr;
+ p->plen = plen;
+ p->ifindex = ifindex;
+ p->label = label;
+ write_unlock_bh(&addrselect_label_lock);
+ return 0;
+}
+
+int ipv6_addrselect_del_label(struct in6_addr *addr, int plen)
+{
+ struct ipv6_addrselect_label *p, *p_last;
+
+ write_lock_bh(&addrselect_label_lock);
+ p_last = ipv6_addrselect_label_table;
+ for (p = ipv6_addrselect_label_table;
+ p;
+ p = p->next) {
+ if (ipv6_addr_diff(addr, &p->addr) >= plen && plen == p->plen) {
+ if (ipv6_addrselect_label_table == p) {
+ ipv6_addrselect_label_table = p->next;
+ } else {
+ p_last->next = p->next;
+ }
+ kfree(p);
+ write_unlock_bh(&addrselect_label_lock);
+ return 0;
+ }
+ p_last = p;
+ }
+ write_unlock_bh(&addrselect_label_lock);
+ return -ENOENT;
+}
+
+int addrconf_label_ioctl(unsigned int cmd, void *arg)
+{
+ struct in6_addrlabelreq req;
+ int err = -EINVAL;
+
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ switch(cmd) {
+ case SIOCSDADDRLABEL:
+ err = copy_from_user(&req, arg, sizeof(struct in6_addrlabelreq));
+ if (err)
+ return -EFAULT;
+ err = ipv6_addrselect_add_label(req.ifindex, &req.addr, req.plen, req.label);
+ break;
+
+ case SIOCDDADDRLABEL:
+ err = copy_from_user(&req, arg, sizeof(struct in6_addrlabelreq));
+ if (err)
+ return -EFAULT;
+ err = ipv6_addrselect_del_label(&req.addr, req.plen);
+ break;
+ }
+ return err;
+}
static u32 ipv6_addrselect_label_lookup(const struct in6_addr *addr,
int ifindex)
@@ -1103,9 +1166,10 @@
int plen, matchlen = -1;
u32 label = 0xffffffff;
+ read_lock_bh(&addrselect_label_lock);
for (p = ipv6_addrselect_label_table;
- p->label != 0xffffffff;
- p++) {
+ p;
+ p = p->next) {
if (ifindex && p->ifindex && ifindex != p->ifindex)
continue;
plen = ipv6_addr_diff(addr, &p->addr);
@@ -1114,9 +1178,177 @@
matchlen = plen;
label = p->label;
}
+ read_unlock_bh(&addrselect_label_lock);
return label;
}
+static struct ipv6_addrselect_label ipv6_addrselect_label_init_table[] = {
+ /* prefix = ::1/128, label = 0 */
+ {
+ addr: IN6ADDR_LOOPBACK_INIT,
+ plen: 128,
+ label: 0,
+ },
+ /* prefix = ::/0, label = 1 */
+ {
+ label: 1,
+ },
+ /* prefix = 2002::/16, label = 2 */
+ {
+ addr: {{{ 0x20,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }}},
+ plen: 16,
+ label: 2,
+ },
+ /* prefix = ::/96, label = 3 */
+ {
+ plen: 96,
+ label: 3,
+ },
+ /* prefix = ::ffff:0:0/96, label = 4 */
+ {
+ addr: {{{ 0,0,0,0,0,0,0,0,0,0xff,0xff,0,0,0,0 }}},
+ plen: 96,
+ label: 4,
+ },
+ /* sentinel */
+ {
+ label: 0xffffffff,
+ }
+};
+
+void ipv6_addrselect_init(void)
+{
+ struct ipv6_addrselect_label **pnext, *p0;
+
+ for (p0 = ipv6_addrselect_label_init_table,
+ pnext = &ipv6_addrselect_label_table;
+ p0->label != 0xffffffff;
+ p0++,
+ pnext = &(*pnext)->next) {
+ *pnext = kmalloc(sizeof(**pnext), GFP_ATOMIC);
+ if (*pnext == NULL) {
+ printk(KERN_WARNING
+ "%s(): failed to allocate memory\n",
+ __FUNCTION__);
+ break;
+ }
+ memcpy(*pnext, p0, sizeof(**pnext));
+ }
+};
+
+void ipv6_addrselect_cleanup(void)
+{
+ struct ipv6_addrselect_label *p, *pnext;
+
+ write_lock_bh(&addrselect_label_lock);
+ if ((pnext = ipv6_addrselect_label_table)) {
+ ipv6_addrselect_label_table = NULL;
+ do {
+ p = pnext;
+ pnext = p->next;
+ kfree(p);
+ } while (pnext);
+ }
+ write_unlock_bh(&addrselect_label_lock);
+}
+
+
+#ifdef CONFIG_PROC_FS
+
+static struct ipv6_addrselect_label *addrsel_pt_get_first(struct seq_file *seq)
+{
+ return ipv6_addrselect_label_table;
+}
+
+static struct ipv6_addrselect_label *addrsel_pt_get_next(struct seq_file *seq, struct ipv6_addrselect_label *p)
+{
+ p = p->next;
+ return p;
+}
+
+static struct ipv6_addrselect_label *addrsel_pt_get_idx(struct seq_file *seq, loff_t pos)
+{
+ struct ipv6_addrselect_label *p = addrsel_pt_get_first(seq);
+
+ if (p)
+ while(pos && (p = addrsel_pt_get_next(seq, p)) != NULL)
+ --pos;
+ return pos ? NULL : p;
+}
+
+static void *addrsel_pt_seq_start(struct seq_file *seq, loff_t *pos)
+{
+ read_lock_bh(&addrselect_label_lock);
+ return addrsel_pt_get_idx(seq, *pos);
+}
+
+static void *addrsel_pt_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct ipv6_addrselect_label *p;
+
+ p = addrsel_pt_get_next(seq, v);
+ ++*pos;
+ return p;
+}
+
+static void addrsel_pt_seq_stop(struct seq_file *seq, void *v)
+{
+ read_unlock_bh(&addrselect_label_lock);
+}
+
+static int addrsel_pt_seq_show(struct seq_file *seq, void *v)
+{
+ struct ipv6_addrselect_label *p = (struct ipv6_addrselect_label *)v;
+ seq_printf(seq,
+ "%04x%04x%04x%04x%04x%04x%04x%04x %02x %02x %02x\n",
+ NIP6(p->addr),
+ p->plen,
+ p->ifindex,
+ p->label);
+ return 0;
+}
+
+static struct seq_operations addrsel_pt_seq_ops = {
+ .start = addrsel_pt_seq_start,
+ .next = addrsel_pt_seq_next,
+ .show = addrsel_pt_seq_show,
+ .stop = addrsel_pt_seq_stop,
+};
+
+static int addrsel_pt_seq_open(struct inode *inode, struct file *file)
+{
+ struct seq_file *seq;
+ int rc = -ENOMEM;
+
+ rc = seq_open(file, &addrsel_pt_seq_ops);
+ if (!rc)
+ seq = file->private_data;
+
+ return rc;
+}
+
+static struct file_operations addrsel_pt_fops = {
+ .owner = THIS_MODULE,
+ .open = addrsel_pt_seq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+};
+
+int __init addrsel_pt_proc_init(void)
+{
+ if (!proc_net_fops_create("addrsel_pt", S_IRUGO, &addrsel_pt_fops))
+ return -ENOMEM;
+ return 0;
+}
+
+void addrsel_pt_proc_exit(void)
+{
+ proc_net_remove("addrsel_pt");
+}
+
+#endif /* CONFIG_PROC_FS */
+
int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
{
const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
@@ -3429,6 +3661,7 @@
register_sysctl_table(addrconf_sysctl.addrconf_root_dir, 0);
addrconf_sysctl_register(NULL, &ipv6_devconf_dflt);
#endif
+ ipv6_addrselect_init();
}
void __exit addrconf_cleanup(void)
@@ -3493,7 +3726,10 @@
crypto_free_tfm(tfm);
#endif
+ ipv6_addrselect_cleanup();
+
#ifdef CONFIG_PROC_FS
proc_net_remove("if_inet6");
+ proc_net_remove("addrsel_pt");
#endif
}
diff -urN -X ../dontdiff usagi.0412/kernel/linux26/net/ipv6/af_inet6.c usagi/kernel/linux26/net/ipv6/af_inet6.c
--- usagi.0412/kernel/linux26/net/ipv6/af_inet6.c 2004-03-01 11:51:39.000000000 +0100
+++ usagi/kernel/linux26/net/ipv6/af_inet6.c 2004-04-20 12:28:20.000000000 +0200
@@ -82,6 +82,8 @@
extern void ac6_proc_exit(void);
extern int if6_proc_init(void);
extern void if6_proc_exit(void);
+extern int addrsel_pt_proc_init(void);
+extern void addrsel_pt_proc_exit(void);
#endif
int sysctl_ipv6_bindv6only;
@@ -493,6 +495,9 @@
return addrconf_del_ifaddr((void *) arg);
case SIOCSIFDSTADDR:
return addrconf_set_dstaddr((void *) arg);
+ case SIOCSDADDRLABEL:
+ case SIOCDDADDRLABEL:
+ return (addrconf_label_ioctl(cmd, (void *) arg));
default:
if (!sk->sk_prot->ioctl ||
(err = sk->sk_prot->ioctl(sk, cmd, arg)) == -ENOIOCTLCMD)
@@ -790,6 +795,8 @@
goto proc_anycast6_fail;
if (if6_proc_init())
goto proc_if6_fail;
+ if (addrsel_pt_proc_init())
+ goto proc_addrsel_pt_fail;
#endif
ipv6_packet_init();
ip6_route_init();
@@ -810,6 +817,8 @@
return 0;
#ifdef CONFIG_PROC_FS
+proc_addrsel_pt_fail:
+ if6_proc_exit();
proc_if6_fail:
ac6_proc_exit();
proc_anycast6_fail:
@@ -842,6 +851,7 @@
/* First of all disallow new sockets creation. */
sock_unregister(PF_INET6);
#ifdef CONFIG_PROC_FS
+ addrsel_pt_proc_exit();
if6_proc_exit();
ac6_proc_exit();
ipv6_misc_proc_exit();