From 6d20a77450fc834ca0218a03cb03cbf3706fb90e Mon Sep 17 00:00:00 2001 From: Ruslan Ermilov Date: Thu, 27 Apr 2000 17:37:03 +0000 Subject: [PATCH] Load Sharing using IP Network Address Translation (RFC 2391, LSNAT). LSNAT links are first created by either PacketAliasRedirectPort() or PacketAliasRedirectAddress() and then set up by one or more calls to PacketAliasAddServer(). --- lib/libalias/alias.h | 5 ++ lib/libalias/alias_db.c | 112 ++++++++++++++++++++++++-------- lib/libalias/libalias.3 | 60 +++++++++++++++++ sys/netinet/libalias/alias.h | 5 ++ sys/netinet/libalias/alias_db.c | 112 ++++++++++++++++++++++++-------- sys/netinet/libalias/libalias.3 | 60 +++++++++++++++++ 6 files changed, 300 insertions(+), 54 deletions(-) diff --git a/lib/libalias/alias.h b/lib/libalias/alias.h index 2285d97e3072..9f15579832a2 100644 --- a/lib/libalias/alias.h +++ b/lib/libalias/alias.h @@ -51,6 +51,11 @@ struct alias_link; struct in_addr, u_short, u_char); + extern int + PacketAliasAddServer(struct alias_link *link, + struct in_addr addr, + u_short port); + extern int PacketAliasPptp(struct in_addr); diff --git a/lib/libalias/alias_db.c b/lib/libalias/alias_db.c index 431a757540a5..bc020f35e4b4 100644 --- a/lib/libalias/alias_db.c +++ b/lib/libalias/alias_db.c @@ -237,6 +237,13 @@ struct tcp_dat int fwhole; /* Which firewall record is used for this hole? */ }; +struct server /* LSNAT server pool (circular list) */ +{ + struct in_addr addr; + u_short port; + struct server *next; +}; + struct alias_link /* Main data structure */ { struct in_addr src_addr; /* Address and port information */ @@ -247,6 +254,7 @@ struct alias_link /* Main data structure */ u_short dst_port; u_short alias_port; u_short proxy_port; + struct server *server; int link_type; /* Type of link: TCP, UDP, ICMP, PPTP, frag */ @@ -778,6 +786,17 @@ DeleteLink(struct alias_link *link) ClearFWHole(link); #endif +/* Free memory allocated for LSNAT server pool */ + if (link->server != NULL) { + struct server *head, *curr, *next; + + head = curr = link->server; + do { + next = curr->next; + free(curr); + } while ((curr = next) != head); + } + /* Adjust output table pointers */ link_last = link->last_out; link_next = link->next_out; @@ -871,6 +890,7 @@ AddLink(struct in_addr src_addr, link->src_port = src_port; link->dst_port = dst_port; link->proxy_port = 0; + link->server = NULL; link->link_type = link_type; link->sockfd = -1; link->flags = 0; @@ -1044,6 +1064,7 @@ _FindLinkOut(struct in_addr src_addr, while (link != NULL) { if (link->src_addr.s_addr == src_addr.s_addr + && link->server == NULL && link->dst_addr.s_addr == dst_addr.s_addr && link->dst_port == dst_port && link->src_port == src_port @@ -1207,39 +1228,39 @@ _FindLinkIn(struct in_addr dst_addr, if (link_fully_specified != NULL) { link_fully_specified->timestamp = timeStamp; - return link_fully_specified; + link = link_fully_specified; } else if (link_unknown_dst_port != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_port, - link_unknown_dst_port->src_addr, dst_addr, alias_addr, - link_unknown_dst_port->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_port; - } + link = link_unknown_dst_port; else if (link_unknown_dst_addr != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_addr, - link_unknown_dst_addr->src_addr, dst_addr, alias_addr, - link_unknown_dst_addr->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_addr; - } + link = link_unknown_dst_addr; else if (link_unknown_all != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_all, - link_unknown_all->src_addr, dst_addr, alias_addr, - link_unknown_all->src_port, dst_port, alias_port, - link_type) - : link_unknown_all; - } + link = link_unknown_all; else + return (NULL); + + if (replace_partial_links && + (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) { - return(NULL); + struct in_addr src_addr; + u_short src_port; + + if (link->server != NULL) { /* LSNAT link */ + src_addr = link->server->addr; + src_port = link->server->port; + link->server = link->server->next; + } else { + src_addr = link->src_addr; + src_port = link->src_port; + } + + link = ReLink(link, + src_addr, dst_addr, alias_addr, + src_port, dst_port, alias_port, + link_type); } + + return (link); } static struct alias_link * @@ -1527,7 +1548,13 @@ FindOriginalAddress(struct in_addr alias_addr) } else { - if (link->src_addr.s_addr == INADDR_ANY) + if (link->server != NULL) { /* LSNAT link */ + struct in_addr src_addr; + + src_addr = link->server->addr; + link->server = link->server->next; + return (src_addr); + } else if (link->src_addr.s_addr == INADDR_ANY) return aliasAddress; else return link->src_addr; @@ -2035,6 +2062,7 @@ UninitPacketAliasLog(void) -- "outside world" means other than alias*.c routines -- PacketAliasRedirectPort() + PacketAliasAddServer() PacketAliasRedirectPptp() PacketAliasRedirectAddr() PacketAliasRedirectDelete() @@ -2092,6 +2120,36 @@ PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, return link; } +/* Add server to the pool of servers */ +int +PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port) +{ + struct server *server; + + server = malloc(sizeof(struct server)); + + if (server != NULL) { + struct server *head; + + server->addr = addr; + server->port = port; + + head = link->server; + if (head == NULL) + server->next = server; + else { + struct server *s; + + for (s = head; s->next != head; s = s->next); + s->next = server; + server->next = head; + } + link->server = server; + return (0); + } else + return (-1); +} + /* Translate PPTP packets to a machine on the inside * XXX This function is made obsolete by PacketAliasRedirectPptp(). */ diff --git a/lib/libalias/libalias.3 b/lib/libalias/libalias.3 index 42840af9bf7b..36788d5fe834 100644 --- a/lib/libalias/libalias.3 +++ b/lib/libalias/libalias.3 @@ -376,6 +376,14 @@ is called to change the address after .Fn PacketAliasRedirectPort is called, a zero reference will track this change. .Pp +If the link is further set up to operate for a load sharing, then +.Fa local_addr +and +.Fa local_port +are ignored, and are selected dynamically from the server pool, as described in +.Fn PacketAliasAddServer +below. +.Pp If .Fa remote_addr is zero, this indicates to redirect packets from any remote address. @@ -434,6 +442,12 @@ is called to change the address after .Fn PacketAliasRedirectAddr is called, a zero reference will track this change. .Pp +If the link is further set up to operate for a load sharing, then +.Fa local_addr +is ignored, and is selected dynamically from the server pool, as described in +.Fn PacketAliasAddServer +below. +.Pp If subsequent calls to .Fn PacketAliasRedirectAddr use the same aliasing address, all new incoming traffic to this aliasing @@ -471,6 +485,52 @@ If is returned, then the function call did not complete successfully. .Ed .Pp +.Ft int +.Fo PacketAliasAddServer +.Fa "struct alias_link *link" +.Fa "struct in_addr addr" +.Fa "u_short port" +.Fc +.Bd -ragged -offset indent +This function sets the +.Fa link +up for Load Sharing using IP Network Address Translation (RFC 2391, LSNAT). +LSNAT operates as follows. +A client attempts to access a server by using the server virtual address. +The LSNAT router transparently redirects the request to one of the hosts +in server pool, selected using a real-time load sharing algorithm. +Multiple sessions may be initiated from the same client, and each session +could be directed to a different host based on load balance across server +pool hosts at the time. +If load share is desired for just a few specific services, the configuration +on LSNAT could be defined to restrict load share for just the services +desired. +.Pp +Currently, only the simplest selection algorithm is implemented, where a +host is selected on a round-robin basis only, without regard to load on +the host. +.Pp +First, the +.Fa link +is created by either +.Fn PacketAliasRedirectPort +or +.Fn PacketAliasRedirectAddr . +Then, +.Fn PacketAliasAddServer +is called multiple times to add entries to the +.Fa link Ns 's +server pool. +.Pp +For links created with +.Fn PacketAliasRedirectAddr , +the +.Fa port +argument is ignored and could have any value, e.g. htons(~0). +.Pp +This function returns 0 on success, -1 otherwise. +.Ed +.Pp .Ft void .Fn PacketAliasRedirectDelete "struct alias_link *link" .Bd -ragged -offset indent diff --git a/sys/netinet/libalias/alias.h b/sys/netinet/libalias/alias.h index 2285d97e3072..9f15579832a2 100644 --- a/sys/netinet/libalias/alias.h +++ b/sys/netinet/libalias/alias.h @@ -51,6 +51,11 @@ struct alias_link; struct in_addr, u_short, u_char); + extern int + PacketAliasAddServer(struct alias_link *link, + struct in_addr addr, + u_short port); + extern int PacketAliasPptp(struct in_addr); diff --git a/sys/netinet/libalias/alias_db.c b/sys/netinet/libalias/alias_db.c index 431a757540a5..bc020f35e4b4 100644 --- a/sys/netinet/libalias/alias_db.c +++ b/sys/netinet/libalias/alias_db.c @@ -237,6 +237,13 @@ struct tcp_dat int fwhole; /* Which firewall record is used for this hole? */ }; +struct server /* LSNAT server pool (circular list) */ +{ + struct in_addr addr; + u_short port; + struct server *next; +}; + struct alias_link /* Main data structure */ { struct in_addr src_addr; /* Address and port information */ @@ -247,6 +254,7 @@ struct alias_link /* Main data structure */ u_short dst_port; u_short alias_port; u_short proxy_port; + struct server *server; int link_type; /* Type of link: TCP, UDP, ICMP, PPTP, frag */ @@ -778,6 +786,17 @@ DeleteLink(struct alias_link *link) ClearFWHole(link); #endif +/* Free memory allocated for LSNAT server pool */ + if (link->server != NULL) { + struct server *head, *curr, *next; + + head = curr = link->server; + do { + next = curr->next; + free(curr); + } while ((curr = next) != head); + } + /* Adjust output table pointers */ link_last = link->last_out; link_next = link->next_out; @@ -871,6 +890,7 @@ AddLink(struct in_addr src_addr, link->src_port = src_port; link->dst_port = dst_port; link->proxy_port = 0; + link->server = NULL; link->link_type = link_type; link->sockfd = -1; link->flags = 0; @@ -1044,6 +1064,7 @@ _FindLinkOut(struct in_addr src_addr, while (link != NULL) { if (link->src_addr.s_addr == src_addr.s_addr + && link->server == NULL && link->dst_addr.s_addr == dst_addr.s_addr && link->dst_port == dst_port && link->src_port == src_port @@ -1207,39 +1228,39 @@ _FindLinkIn(struct in_addr dst_addr, if (link_fully_specified != NULL) { link_fully_specified->timestamp = timeStamp; - return link_fully_specified; + link = link_fully_specified; } else if (link_unknown_dst_port != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_port, - link_unknown_dst_port->src_addr, dst_addr, alias_addr, - link_unknown_dst_port->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_port; - } + link = link_unknown_dst_port; else if (link_unknown_dst_addr != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_dst_addr, - link_unknown_dst_addr->src_addr, dst_addr, alias_addr, - link_unknown_dst_addr->src_port, dst_port, alias_port, - link_type) - : link_unknown_dst_addr; - } + link = link_unknown_dst_addr; else if (link_unknown_all != NULL) - { - return replace_partial_links - ? ReLink(link_unknown_all, - link_unknown_all->src_addr, dst_addr, alias_addr, - link_unknown_all->src_port, dst_port, alias_port, - link_type) - : link_unknown_all; - } + link = link_unknown_all; else + return (NULL); + + if (replace_partial_links && + (link->flags & LINK_PARTIALLY_SPECIFIED || link->server != NULL)) { - return(NULL); + struct in_addr src_addr; + u_short src_port; + + if (link->server != NULL) { /* LSNAT link */ + src_addr = link->server->addr; + src_port = link->server->port; + link->server = link->server->next; + } else { + src_addr = link->src_addr; + src_port = link->src_port; + } + + link = ReLink(link, + src_addr, dst_addr, alias_addr, + src_port, dst_port, alias_port, + link_type); } + + return (link); } static struct alias_link * @@ -1527,7 +1548,13 @@ FindOriginalAddress(struct in_addr alias_addr) } else { - if (link->src_addr.s_addr == INADDR_ANY) + if (link->server != NULL) { /* LSNAT link */ + struct in_addr src_addr; + + src_addr = link->server->addr; + link->server = link->server->next; + return (src_addr); + } else if (link->src_addr.s_addr == INADDR_ANY) return aliasAddress; else return link->src_addr; @@ -2035,6 +2062,7 @@ UninitPacketAliasLog(void) -- "outside world" means other than alias*.c routines -- PacketAliasRedirectPort() + PacketAliasAddServer() PacketAliasRedirectPptp() PacketAliasRedirectAddr() PacketAliasRedirectDelete() @@ -2092,6 +2120,36 @@ PacketAliasRedirectPort(struct in_addr src_addr, u_short src_port, return link; } +/* Add server to the pool of servers */ +int +PacketAliasAddServer(struct alias_link *link, struct in_addr addr, u_short port) +{ + struct server *server; + + server = malloc(sizeof(struct server)); + + if (server != NULL) { + struct server *head; + + server->addr = addr; + server->port = port; + + head = link->server; + if (head == NULL) + server->next = server; + else { + struct server *s; + + for (s = head; s->next != head; s = s->next); + s->next = server; + server->next = head; + } + link->server = server; + return (0); + } else + return (-1); +} + /* Translate PPTP packets to a machine on the inside * XXX This function is made obsolete by PacketAliasRedirectPptp(). */ diff --git a/sys/netinet/libalias/libalias.3 b/sys/netinet/libalias/libalias.3 index 42840af9bf7b..36788d5fe834 100644 --- a/sys/netinet/libalias/libalias.3 +++ b/sys/netinet/libalias/libalias.3 @@ -376,6 +376,14 @@ is called to change the address after .Fn PacketAliasRedirectPort is called, a zero reference will track this change. .Pp +If the link is further set up to operate for a load sharing, then +.Fa local_addr +and +.Fa local_port +are ignored, and are selected dynamically from the server pool, as described in +.Fn PacketAliasAddServer +below. +.Pp If .Fa remote_addr is zero, this indicates to redirect packets from any remote address. @@ -434,6 +442,12 @@ is called to change the address after .Fn PacketAliasRedirectAddr is called, a zero reference will track this change. .Pp +If the link is further set up to operate for a load sharing, then +.Fa local_addr +is ignored, and is selected dynamically from the server pool, as described in +.Fn PacketAliasAddServer +below. +.Pp If subsequent calls to .Fn PacketAliasRedirectAddr use the same aliasing address, all new incoming traffic to this aliasing @@ -471,6 +485,52 @@ If is returned, then the function call did not complete successfully. .Ed .Pp +.Ft int +.Fo PacketAliasAddServer +.Fa "struct alias_link *link" +.Fa "struct in_addr addr" +.Fa "u_short port" +.Fc +.Bd -ragged -offset indent +This function sets the +.Fa link +up for Load Sharing using IP Network Address Translation (RFC 2391, LSNAT). +LSNAT operates as follows. +A client attempts to access a server by using the server virtual address. +The LSNAT router transparently redirects the request to one of the hosts +in server pool, selected using a real-time load sharing algorithm. +Multiple sessions may be initiated from the same client, and each session +could be directed to a different host based on load balance across server +pool hosts at the time. +If load share is desired for just a few specific services, the configuration +on LSNAT could be defined to restrict load share for just the services +desired. +.Pp +Currently, only the simplest selection algorithm is implemented, where a +host is selected on a round-robin basis only, without regard to load on +the host. +.Pp +First, the +.Fa link +is created by either +.Fn PacketAliasRedirectPort +or +.Fn PacketAliasRedirectAddr . +Then, +.Fn PacketAliasAddServer +is called multiple times to add entries to the +.Fa link Ns 's +server pool. +.Pp +For links created with +.Fn PacketAliasRedirectAddr , +the +.Fa port +argument is ignored and could have any value, e.g. htons(~0). +.Pp +This function returns 0 on success, -1 otherwise. +.Ed +.Pp .Ft void .Fn PacketAliasRedirectDelete "struct alias_link *link" .Bd -ragged -offset indent