Add ip_vs_schedule_v6() and ip_vs_sched_persist_v6() functions for
scheduling IPv6 connections.
Signed-off-by: Julius R. Volz <juliusv@xxxxxxxxxx>
2 files changed, 241 insertions(+), 0 deletions(-)
diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h
index 6a58dff..8d28d98 100644
--- a/include/net/ip_vs.h
+++ b/include/net/ip_vs.h
@@ -991,6 +991,11 @@ extern struct ip_vs_scheduler *ip_vs_scheduler_get(const
char *sched_name);
extern void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler);
extern struct ip_vs_conn *
ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb);
+#ifdef CONFIG_IP_VS_IPV6
+extern struct ip_vs_conn *
+ip_vs_schedule_v6(struct ip_vs_service *svc, const struct sk_buff *skb);
+#endif
+
extern int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
struct ip_vs_protocol *pp);
diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c
index 9a3d0df..ccd95ff 100644
--- a/net/netfilter/ipvs/ip_vs_core.c
+++ b/net/netfilter/ipvs/ip_vs_core.c
@@ -333,6 +333,180 @@ ip_vs_sched_persist(struct ip_vs_service *svc,
return cp;
}
+#ifdef CONFIG_IP_VS_IPV6
+static struct ip_vs_conn *
+ip_vs_sched_persist_v6(struct ip_vs_service *svc,
+ const struct sk_buff *skb,
+ __be16 ports[2])
+{
+ struct ip_vs_conn *cp = NULL;
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ struct ip_vs_dest *dest;
+ struct ip_vs_conn *ct;
+ __be16 dport; /* destination port to forward */
+ struct in6_addr snet; /* source network of the client, after masking
*/
+
+ /* Mask saddr with the netmask to adjust template granularity */
+ ipv6_addr_prefix(&snet, &iph->saddr, svc->netmask);
+
+ IP_VS_DBG(6, "p-schedule: src " NIP6_FMT ":%u dest " NIP6_FMT ":%u "
+ "mnet " NIP6_FMT "\n",
+ NIP6(iph->saddr), ntohs(ports[0]),
+ NIP6(iph->daddr), ntohs(ports[1]),
+ NIP6(snet));
+
+ /*
+ * As far as we know, FTP is a very complicated network protocol, and
+ * it uses control connection and data connections. For active FTP,
+ * FTP server initialize data connection to the client, its source port
+ * is often 20. For passive FTP, FTP server tells the clients the port
+ * that it passively listens to, and the client issues the data
+ * connection. In the tunneling or direct routing mode, the load
+ * balancer is on the client-to-server half of connection, the port
+ * number is unknown to the load balancer. So, a conn template like
+ * <caddr, 0, vaddr, 0, daddr, 0> is created for persistent FTP
+ * service, and a template like <caddr, 0, vaddr, vport, daddr, dport>
+ * is created for other persistent services.
+ */
+ if (ports[1] == svc->port) {
+ /* Check if a template already exists */
+ if (svc->port != FTPPORT)
+ ct = ip_vs_ct_in_get_v6(iph->nexthdr, &snet, 0,
+ &iph->daddr, ports[1]);
+ else
+ ct = ip_vs_ct_in_get_v6(iph->nexthdr, &snet, 0,
+ &iph->daddr, 0);
+
+ if (!ct || !ip_vs_check_template(ct)) {
+ /*
+ * No template found or the dest of the connection
+ * template is not available.
+ */
+ dest = svc->scheduler->schedule(svc, skb);
+ if (dest == NULL) {
+ IP_VS_DBG(1, "p-schedule: no dest found.\n");
+ return NULL;
+ }
+
+ /*
+ * Create a template like <protocol,caddr,0,
+ * vaddr,vport,daddr,dport> for non-ftp service,
+ * and <protocol,caddr,0,vaddr,0,daddr,0>
+ * for ftp service.
+ */
+ if (svc->port != FTPPORT)
+ ct = ip_vs_conn_new_v6(iph->nexthdr,
+ &snet, 0,
+ &iph->daddr,
+ ports[1],
+ &dest->addr.v6,
dest->port,
+ IP_VS_CONN_F_TEMPLATE,
+ dest);
+ else
+ ct = ip_vs_conn_new_v6(iph->nexthdr,
+ &snet, 0,
+ &iph->daddr, 0,
+ &dest->addr.v6, 0,
+ IP_VS_CONN_F_TEMPLATE,
+ dest);
+ if (ct == NULL)
+ return NULL;
+
+ ct->timeout = svc->timeout;
+ } else {
+ /* set destination with the found template */
+ dest = ct->dest;
+ }
+ dport = dest->port;
+ } else {
+ /*
+ * Note: persistent fwmark-based services and persistent
+ * port zero service are handled here.
+ * fwmark template: <IPPROTO_IP,caddr,0,fwmark,0,daddr,0>
+ * port zero template: <protocol,caddr,0,vaddr,0,daddr,0>
+ */
+ if (svc->fwmark) {
+ struct in6_addr fwmark = {
+ .s6_addr32 = {0, 0, 0, htonl(svc->fwmark)}
+ };
+
+ ct = ip_vs_ct_in_get_v6(IPPROTO_IP, &snet, 0,
+ &fwmark, 0);
+ } else
+ ct = ip_vs_ct_in_get_v6(iph->nexthdr, &snet, 0,
+ &iph->daddr, 0);
+
+ if (!ct || !ip_vs_check_template(ct)) {
+ /*
+ * If it is not persistent port zero, return NULL,
+ * otherwise create a connection template.
+ */
+ if (svc->port)
+ return NULL;
+
+ dest = svc->scheduler->schedule(svc, skb);
+ if (dest == NULL) {
+ IP_VS_DBG(1, "p-schedule: no dest found.\n");
+ return NULL;
+ }
+
+ /*
+ * Create a template according to the service
+ */
+ if (svc->fwmark) {
+ struct in6_addr fwmark = {
+ .s6_addr32 = {0, 0, 0,
htonl(svc->fwmark)}
+ };
+
+ ct = ip_vs_conn_new_v6(IPPROTO_IP,
+ &snet, 0,
+ &fwmark, 0,
+ &dest->addr.v6, 0,
+ IP_VS_CONN_F_TEMPLATE,
+ dest);
+ }
+ else
+ ct = ip_vs_conn_new_v6(iph->nexthdr,
+ &snet, 0,
+ &iph->daddr, 0,
+ &dest->addr.v6, 0,
+ IP_VS_CONN_F_TEMPLATE,
+ dest);
+ if (ct == NULL)
+ return NULL;
+
+ ct->timeout = svc->timeout;
+ } else {
+ /* set destination with the found template */
+ dest = ct->dest;
+ }
+ dport = ports[1];
+ }
+
+ /*
+ * Create a new connection according to the template
+ */
+ cp = ip_vs_conn_new_v6(iph->nexthdr,
+ &iph->saddr, ports[0],
+ &iph->daddr, ports[1],
+ &dest->addr.v6, dport,
+ 0,
+ dest);
+ if (cp == NULL) {
+ ip_vs_conn_put(ct);
+ return NULL;
+ }
+
+ /*
+ * Add its control
+ */
+ ip_vs_control_add(cp, ct);
+ ip_vs_conn_put(ct);
+
+ ip_vs_conn_stats(cp, svc);
+ return cp;
+}
+#endif
/*
* IPVS main scheduling function
@@ -400,6 +574,68 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct
sk_buff *skb)
return cp;
}
+#ifdef CONFIG_IP_VS_IPV6
+struct ip_vs_conn *
+ip_vs_schedule_v6(struct ip_vs_service *svc, const struct sk_buff *skb)
+{
+ struct ip_vs_conn *cp = NULL;
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ struct ip_vs_dest *dest;
+ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, sizeof(struct ipv6hdr),
+ sizeof(_ports), _ports);
+ if (pptr == NULL)
+ return NULL;
+
+ /*
+ * Persistent service
+ */
+ if (svc->flags & IP_VS_SVC_F_PERSISTENT)
+ return ip_vs_sched_persist_v6(svc, skb, pptr);
+
+ /*
+ * Non-persistent service
+ */
+ if (!svc->fwmark && pptr[1] != svc->port) {
+ if (!svc->port)
+ IP_VS_ERR("Schedule: port zero only supported "
+ "in persistent services, "
+ "check your ipvs configuration\n");
+ return NULL;
+ }
+
+ dest = svc->scheduler->schedule(svc, skb);
+ if (dest == NULL) {
+ IP_VS_DBG(1, "Schedule: no dest found.\n");
+ return NULL;
+ }
+
+ /*
+ * Create a connection entry.
+ */
+ cp = ip_vs_conn_new_v6(iph->nexthdr,
+ &iph->saddr, pptr[0],
+ &iph->daddr, pptr[1],
+ &dest->addr.v6, dest->port?dest->port:pptr[1],
+ 0,
+ dest);
+ if (cp == NULL)
+ return NULL;
+
+ IP_VS_DBG(6, "Schedule fwd:%c c:" NIP6_FMT ":%u v:" NIP6_FMT ":%u "
+ "d:" NIP6_FMT ":%u conn->flags:%X conn->refcnt:%d\n",
+ ip_vs_fwd_tag(cp),
+ NIP6(cp->caddr.v6), ntohs(cp->cport),
+ NIP6(cp->vaddr.v6), ntohs(cp->vport),
+ NIP6(cp->daddr.v6), ntohs(cp->dport),
+ cp->flags, atomic_read(&cp->refcnt));
+
+ ip_vs_conn_stats(cp, svc);
+ return cp;
+}
+#endif
+
/*
* Pass or drop the packet.
--
1.5.3.6
--
To unsubscribe from this list: send the line "unsubscribe lvs-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
|