patch-1.3.51 linux/net/core/net_alias.c
Next file: linux/net/core/sock.c
Previous file: linux/net/core/dev.c
Back to the patch index
Back to the overall index
- Lines: 664
- Date:
Tue Dec 26 06:03:01 1995
- Orig file:
v1.3.50/linux/net/core/net_alias.c
- Orig date:
Wed Dec 13 09:02:47 1995
diff -u --recursive --new-file v1.3.50/linux/net/core/net_alias.c linux/net/core/net_alias.c
@@ -1,7 +1,8 @@
/*
- * NET_ALIAS device aliasing module.
+ * NET_ALIAS network device aliasing module.
*
- * Version: @(#)net_alias.c 0.42 12/11/95
+ *
+ * Version: @(#)net_alias.c 0.43 12/20/95
*
* Authors: Juan Jose Ciarlante, <jjciarla@raiz.uncu.edu.ar>
* Marcelo Fabian Roccasalva, <mfroccas@raiz.uncu.edu.ar>
@@ -13,15 +14,13 @@
* - fast hashed alias address lookup
* - net_alias_type objs registration/unreg., module-ables.
* - /proc/net/aliases & /proc/net/alias_types entries
+ * Fixes:
+ * JJC : several net_alias_type func. renamed.
+ * JJC : net_alias_type object methods now pass *this.
+ * JJC : xxx_rcv device selection based on <src,dst> addrs
*
* FIXME:
* - User calls sleep/wake_up locking.
- * - Define a way to select the "best" alias device for an incoming
- * packet to allow xxx_rcv() device switching based ALSO on pkt's
- * src address (this would require a routing query).
- * Related stuff:
- * IP: Test routing between aliases (possible ICMP redirects).
- * IP: ARP proxy entries attached to aliases are not visible.
*
*
* This program is free software; you can redistribute it and/or
@@ -37,6 +36,7 @@
#include <linux/notifier.h>
#include <linux/if.h>
#include <linux/inet.h>
+#include <linux/in.h>
#include <linux/proc_fs.h>
#include <linux/stat.h>
@@ -68,7 +68,7 @@
static void net_alias_free(struct device *dev);
/*
- * net_alias_type base array, will hold net_alias_type objects.
+ * net_alias_type base array, will hold net_alias_type obj hashed list heads.
*/
struct net_alias_type *nat_base[16];
@@ -99,7 +99,7 @@
nat_addr32(struct net_alias_type *nat, struct sockaddr *sa)
{
if (nat->get_addr32)
- return nat->get_addr32(sa);
+ return nat->get_addr32(nat, sa);
else
return (*(struct sockaddr_in *)sa).sin_addr.s_addr;
}
@@ -122,7 +122,7 @@
/*
* get hash key for supplied net alias type and address
* nat must be !NULL
- * the purpose here is to map an net_alias_type and a generic
+ * the purpose here is to map a net_alias_type and a generic
* address to a hash code.
*/
@@ -166,33 +166,33 @@
static __inline__ int
nat_bind(struct net_alias_type *nat,struct net_alias *alias, struct sockaddr *sa)
{
- if (nat->alias_init_1) nat->alias_init_1(alias, sa);
+ if (nat->alias_init_1) nat->alias_init_1(nat, alias, sa);
return nat_attach_chg(nat, +1);
}
/*
- * unbind alias from type object and call 'done' hook
+ * unbind alias from type object and call alias destructor
*/
static __inline__ int
nat_unbind(struct net_alias_type *nat, struct net_alias *alias)
{
- if (nat->alias_done_1) nat->alias_done_1(alias);
+ if (nat->alias_done_1) nat->alias_done_1(nat, alias);
return nat_attach_chg(nat, -1);
}
/*
- * compare device address with given. if NULL nat->addr_chk,
+ * compare device address with given. if NULL nat->dev_addr_chk,
* compare dev->pa_addr with (sockaddr_in) 32 bits address (IP-ish)
*/
-static __inline__ int nat_addr_chk(struct net_alias_type *nat,
+static __inline__ int nat_dev_addr_chk_1(struct net_alias_type *nat,
struct device *dev, struct sockaddr *sa)
{
- if (nat->addr_chk)
- return nat->addr_chk(dev, sa);
+ if (nat->dev_addr_chk)
+ return nat->dev_addr_chk(nat, dev, sa);
else
return (dev->pa_addr == (*(struct sockaddr_in *)sa).sin_addr.s_addr);
}
@@ -573,6 +573,81 @@
return NULL;
}
+/*
+ * free all main device aliasing stuff
+ * will be called on dev_close(main_dev)
+ */
+
+static void
+net_alias_free(struct device *main_dev)
+{
+ struct net_alias_info *alias_info;
+ struct net_alias *alias;
+ struct net_alias_type *nat;
+ struct device *dev;
+ unsigned long flags;
+
+ /*
+ * do I really have aliases?
+ */
+
+ if (!(alias_info = main_dev->alias_info)) return;
+
+ /*
+ * fast device link "short-circuit": set main_dev->next to
+ * device after last alias
+ */
+
+ save_flags(flags);
+ cli();
+
+ dev = main_dev->next;
+ main_dev->next = alias_info->taildev->next;
+ main_dev->alias_info = NULL;
+ alias_info->taildev->next = NULL;
+
+ restore_flags(flags);
+
+ /*
+ * loop over alias devices, free and dev_close()
+ */
+
+ while (dev)
+ {
+ if (net_alias_is(dev))
+ {
+ alias = dev->my_alias;
+ if (alias->main_dev == main_dev)
+ {
+ /*
+ * unbind alias from alias_type object
+ */
+
+ nat = alias->nat;
+ if (nat)
+ {
+ nat_unbind(nat, alias);
+ } /* else error/printk ??? */
+
+ dev_close(dev);
+ dev = dev->next;
+
+ kfree_s(alias, sizeof(struct net_alias));
+ continue;
+ }
+ else
+ printk("net_alias_free(%s): '%s' is not my alias\n",
+ main_dev->name, alias->name);
+ }
+ else
+ printk("net_alias_free(%s): found a non-alias after device!\n",
+ main_dev->name);
+ dev = dev->next;
+ }
+
+ kfree_s(alias_info, sizeof(alias_info));
+ return;
+}
/*
* dev_get() with added alias naming magic.
@@ -645,23 +720,26 @@
/*
- * rehash alias with address supplied.
+ * rehash alias device with address supplied.
*/
int
-net_alias_rehash(struct net_alias *alias, struct sockaddr *sa)
+net_alias_dev_rehash(struct device *dev, struct sockaddr *sa)
{
struct net_alias_info *alias_info;
- struct net_alias **aliasp;
- struct device *dev;
+ struct net_alias *alias, **aliasp;
+ struct device *main_dev;
unsigned long flags;
struct net_alias_type *o_nat, *n_nat;
unsigned n_hash;
-
+
/*
* defensive ...
*/
+ if (dev == NULL) return -1;
+ if ( (alias = dev->my_alias) == NULL ) return -1;
+
if (!sa)
{
printk("ERROR: net_alias_rehash(): NULL sockaddr passed\n");
@@ -671,8 +749,8 @@
/*
* defensive. should not happen.
*/
-
- if (!(dev = alias->main_dev))
+
+ if ( (main_dev = alias->main_dev) == NULL )
{
printk("ERROR: net_alias_rehash for %s: NULL maindev\n", alias->name);
return -1;
@@ -682,7 +760,7 @@
* defensive. should not happen.
*/
- if (!(alias_info=dev->alias_info))
+ if (!(alias_info=main_dev->alias_info))
{
printk("ERROR: net_alias_rehash for %s: NULL alias_info\n", alias->name);
return -1;
@@ -747,7 +825,7 @@
cli();
/*
- * if type (family) changed unlink from old type object (o_nat)
+ * if type (family) changed, unlink from old type object (o_nat)
* will call o_nat->alias_done_1()
*/
@@ -780,81 +858,6 @@
}
-/*
- * free all main device aliasing stuff
- * will be called on dev_close(main_dev)
- */
-
-static void
-net_alias_free(struct device *main_dev)
-{
- struct net_alias_info *alias_info;
- struct net_alias *alias;
- struct net_alias_type *nat;
- struct device *dev;
- unsigned long flags;
-
- /*
- * do I really have aliases?
- */
-
- if (!(alias_info = main_dev->alias_info)) return;
-
- /*
- * fast device link "short-circuit": set main_dev->next to
- * device after last alias
- */
-
- save_flags(flags);
- cli();
-
- dev = main_dev->next;
- main_dev->next = alias_info->taildev->next;
- main_dev->alias_info = NULL;
- alias_info->taildev->next = NULL;
-
- restore_flags(flags);
-
- /*
- * loop over alias devices, free and dev_close()
- */
-
- while (dev)
- {
- if (net_alias_is(dev))
- {
- alias = dev->my_alias;
- if (alias->main_dev == main_dev)
- {
- /*
- * unbind alias from alias_type object
- */
-
- nat = alias->nat;
- if (nat)
- {
- nat_unbind(nat, alias);
- } /* else error/printk ??? */
-
- dev_close(dev);
- dev = dev->next;
-
- kfree_s(alias, sizeof(struct net_alias));
- continue;
- }
- else
- printk("net_alias_free(%s): '%s' is not my alias\n",
- main_dev->name, alias->name);
- }
- else
- printk("net_alias_free(%s): found a non-alias after device!\n",
- main_dev->name);
- dev = dev->next;
- }
-
- kfree_s(alias_info, sizeof(alias_info));
- return;
-}
/*
@@ -898,7 +901,7 @@
*
*/
-#define NAT_REC_SIZE 64
+#define NET_ALIASES_RECSIZ 64
int net_alias_getinfo(char *buffer, char **start, off_t offset, int length, int dummy)
{
off_t pos=0, begin=0;
@@ -908,7 +911,7 @@
struct net_alias *alias;
struct device *dev;
- len=sprintf(buffer,"%-*s\n",NAT_REC_SIZE-1,"device family address");
+ len=sprintf(buffer,"%-*s\n",NET_ALIASES_RECSIZ-1,"device family address");
for (dev = dev_base; dev ; dev = dev->next)
if (net_alias_is(dev))
{
@@ -921,7 +924,7 @@
*/
if (nat->alias_print_1)
- dlen += nat->alias_print_1(buffer+len+dlen, NAT_REC_SIZE - dlen, alias);
+ dlen += nat->alias_print_1(nat, alias, buffer+len+dlen, NET_ALIASES_RECSIZ - dlen);
else
dlen += sprintf(buffer+len+dlen, "-");
@@ -929,12 +932,12 @@
* fill with spaces if needed
*/
- if (dlen < NAT_REC_SIZE) memset(buffer+len+dlen, ' ', NAT_REC_SIZE - dlen);
+ if (dlen < NET_ALIASES_RECSIZ) memset(buffer+len+dlen, ' ', NET_ALIASES_RECSIZ - dlen);
/*
- * truncate to NAT_REC_SIZE
+ * truncate to NET_ALIASES_RECSIZ
*/
- len += NAT_REC_SIZE;
+ len += NET_ALIASES_RECSIZ;
buffer[len-1] = '\n';
pos=begin+len;
@@ -984,58 +987,39 @@
/*
- * returns alias device with specified address AND flags_1 on AND flags_0 off.
- * intended for main devices.
- * typically called on xxx_rcv() to check if packet's dest address is one
- * of main_dev's alias address.
+ * device aliases address comparison workhorse
+ * no checks for nat and alias_info, must be !NULL
*/
-struct device *
-net_alias_chk(struct device *dev, struct sockaddr *sa,int flags_1, int flags_0)
+static __inline__ struct device *
+nat_addr_chk(struct net_alias_type *nat, struct net_alias_info *alias_info, struct sockaddr *sa, int flags_on, int flags_off)
{
- struct net_alias_info *alias_info = dev->alias_info;
- struct net_alias_type *nat;
struct net_alias *alias;
-
- if (!alias_info) return NULL; /* has aliases? */
-
- /*
- * get alias_type object for sa->sa_family.
- */
-
- nat = nat_getbytype(sa->sa_family);
- if (!nat)
- return 0;
-
for(alias = alias_info->hash_tab[nat_hash_key(nat,sa)];
alias; alias = alias->next)
{
if (alias->dev.family != sa->sa_family) continue;
/*
- * nat_addr_chk will call type specific address cmp function.
+ * nat_dev_addr_chk_1 will call type specific address cmp function.
*/
- if (alias->dev.flags & flags_1 && !(alias->dev.flags & flags_0) &&
- nat_addr_chk(nat,&alias->dev,sa))
+ if (alias->dev.flags & flags_on && !(alias->dev.flags & flags_off) &&
+ nat_dev_addr_chk_1(nat,&alias->dev,sa))
return &alias->dev;
}
return NULL;
}
/*
- * addr_chk enough for protocols whose addr is (fully) stored at pa_addr.
+ * nat_addr_chk enough for protocols whose addr is (fully) stored at pa_addr.
+ * note that nat pointer is ignored because of static comparison.
*/
-struct device *
-net_alias_chk32(struct device *dev, int family, __u32 addr32,
- int flags_1, int flags_0)
+static __inline__ struct device *
+nat_addr_chk32(struct net_alias_type *nat, struct net_alias_info *alias_info, int family, __u32 addr32, int flags_on, int flags_off)
{
- struct net_alias_info *alias_info = dev->alias_info;
struct net_alias *alias;
-
- if (!alias_info) return NULL; /* has aliases? */
-
for (alias=alias_info->hash_tab[HASH(addr32,family)];
alias; alias=alias->next)
{
@@ -1045,13 +1029,212 @@
* "hard" (static) comparison between addr32 and pa_addr.
*/
- if (alias->dev.flags & flags_1 && !(alias->dev.flags & flags_0) &&
+ if (alias->dev.flags & flags_on && !(alias->dev.flags & flags_off) &&
addr32 == alias->dev.pa_addr)
return &alias->dev;
}
return NULL;
}
+/*
+ * returns alias device with specified address AND flags_on AND flags_off,
+ * else NULL.
+ * intended for main devices.
+ */
+
+struct device *
+net_alias_dev_chk(struct device *main_dev, struct sockaddr *sa,int flags_on, int flags_off)
+{
+ struct net_alias_info *alias_info = main_dev->alias_info;
+ struct net_alias_type *nat;
+
+ /*
+ * only if main_dev has aliases
+ */
+
+ if (!alias_info) return NULL;
+
+ /*
+ * get alias_type object for sa->sa_family.
+ */
+
+ nat = nat_getbytype(sa->sa_family);
+ if (!nat)
+ return NULL;
+
+ return nat_addr_chk(nat, alias_info, sa, flags_on, flags_off);
+}
+
+/*
+ * net_alias_dev_chk enough for protocols whose addr is (fully) stored
+ * at pa_addr.
+ */
+
+struct device *
+net_alias_dev_chk32(struct device *main_dev, int family, __u32 addr32,
+ int flags_on, int flags_off)
+{
+ struct net_alias_info *alias_info = main_dev->alias_info;
+
+ /*
+ * only if main_dev has aliases
+ */
+
+ if (!alias_info) return NULL;
+
+ return nat_addr_chk32(NULL, alias_info, family, addr32, flags_on, flags_off);
+}
+
+
+/*
+ * select closest (main or alias) device to <src,dst> addresses given. if no
+ * further info is available, return main_dev (for easier calling arrangment).
+ *
+ * Should be called early at xxx_rcv() time for device selection
+ */
+
+struct device *
+net_alias_dev_rcv_sel(struct device *main_dev, struct sockaddr *sa_src, struct sockaddr *sa_dst)
+{
+ int family;
+ struct net_alias_type *nat;
+ struct net_alias_info *alias_info;
+ struct device *dev;
+
+ if (main_dev == NULL) return NULL;
+
+ /*
+ * if not aliased, dont bother any more
+ */
+
+ if ((alias_info = main_dev->alias_info) == NULL)
+ return main_dev;
+
+ /*
+ * find out family
+ */
+
+ family = (sa_src)? sa_src->sa_family : ((sa_dst)? sa_dst->sa_family : AF_UNSPEC);
+ if (family == AF_UNSPEC) return main_dev;
+
+ /*
+ * get net_alias_type object for this family
+ */
+
+ if ( (nat = nat_getbytype(family)) == NULL ) return main_dev;
+
+ /*
+ * first step: find out if dst addr is main_dev's or one of its aliases'
+ */
+
+ if (sa_dst)
+ {
+ if (nat_dev_addr_chk_1(nat, main_dev,sa_dst))
+ return main_dev;
+
+ dev = nat_addr_chk(nat, alias_info, sa_dst, IFF_UP, 0);
+
+ if (dev != NULL) return dev;
+ }
+
+ /*
+ * second step: find the rcv addr 'closest' alias through nat method call
+ */
+
+ if ( sa_src == NULL || nat->dev_select == NULL) return main_dev;
+ dev = nat->dev_select(nat, main_dev, sa_src);
+
+ if (dev == NULL || dev->family != family) return main_dev;
+
+ /*
+ * dev ok only if it is alias of main_dev
+ */
+
+ dev = net_alias_is(dev)?
+ ( (dev->my_alias->main_dev == main_dev)? dev : NULL) : NULL;
+
+ /*
+ * do not return NULL.
+ */
+
+ return (dev)? dev : main_dev;
+
+}
+
+/*
+ * dev_rcv_sel32: dev_rcv_sel for 'pa_addr' protocols.
+ */
+
+struct device *
+net_alias_dev_rcv_sel32(struct device *main_dev, int family, __u32 src, __u32 dst)
+{
+ struct net_alias_type *nat;
+ struct net_alias_info *alias_info;
+ struct sockaddr_in sin_src;
+ struct device *dev;
+
+ if (main_dev == NULL) return NULL;
+
+ /*
+ * if not aliased, dont bother any more
+ */
+
+ if ((alias_info = main_dev->alias_info) == NULL)
+ return main_dev;
+
+ /*
+ * early return if dst is main_dev's address
+ */
+
+ if (dst == main_dev->pa_addr)
+ return main_dev;
+
+ if (family == AF_UNSPEC) return main_dev;
+
+ /*
+ * get net_alias_type object for this family
+ */
+
+ if ( (nat = nat_getbytype(family)) == NULL ) return main_dev;
+
+ /*
+ * first step: find out if dst address one of main_dev aliases'
+ */
+
+ if (dst)
+ {
+ dev = nat_addr_chk32(nat, alias_info, family, dst, IFF_UP, 0);
+ if (dev) return dev;
+ }
+
+ /*
+ * second step: find the rcv addr 'closest' alias through nat method call
+ */
+
+ if ( src == 0 || nat->dev_select == NULL) return main_dev;
+
+ sin_src.sin_family = family;
+ sin_src.sin_addr.s_addr = src;
+
+ dev = nat->dev_select(nat, main_dev, (struct sockaddr *)&sin_src);
+
+ if (dev == NULL) return main_dev;
+
+ /*
+ * dev ok only if it is alias of main_dev
+ */
+
+ dev = net_alias_is(dev)?
+ ( (dev->my_alias->main_dev == main_dev)? dev : NULL) : NULL;
+
+ /*
+ * do not return NULL.
+ */
+
+ return (dev)? dev : main_dev;
+
+}
+
/*
* device event hook
@@ -1162,3 +1345,4 @@
printk("unregister_net_alias_type(type=%d): not found!\n", nat->type);
return -EINVAL;
}
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this