* [PATCH net-2.6 2/6] be2net: fix a bug in UE detection logic
From: Ajit Khaparde @ 2010-08-22 9:25 UTC (permalink / raw)
To: David Miller; +Cc: netdev
The ONLINE registers can return 0xFFFFFFFF on more than one
occassion. On systems that care, reading these registers could
lead to problems.
So the new code decides that the ASIC has encountered and error
by reading the UE_STATUS_LOW/HIGH registers. AND them with
the mask values and a non-zero result indicates an error.
Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
---
drivers/net/benet/be_main.c | 32 ++++++++------------------------
1 files changed, 8 insertions(+), 24 deletions(-)
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index a5a24e6..6eda7a0 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -1750,26 +1750,7 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget)
return 1;
}
-static inline bool be_detect_ue(struct be_adapter *adapter)
-{
- u32 online0 = 0, online1 = 0;
-
- pci_read_config_dword(adapter->pdev, PCICFG_ONLINE0, &online0);
-
- pci_read_config_dword(adapter->pdev, PCICFG_ONLINE1, &online1);
-
- if (!online0 || !online1) {
- adapter->ue_detected = true;
- dev_err(&adapter->pdev->dev,
- "UE Detected!! online0=%d online1=%d\n",
- online0, online1);
- return true;
- }
-
- return false;
-}
-
-void be_dump_ue(struct be_adapter *adapter)
+void be_detect_dump_ue(struct be_adapter *adapter)
{
u32 ue_status_lo, ue_status_hi, ue_status_lo_mask, ue_status_hi_mask;
u32 i;
@@ -1786,6 +1767,11 @@ void be_dump_ue(struct be_adapter *adapter)
ue_status_lo = (ue_status_lo & (~ue_status_lo_mask));
ue_status_hi = (ue_status_hi & (~ue_status_hi_mask));
+ if (ue_status_lo || ue_status_hi) {
+ adapter->ue_detected = true;
+ dev_err(&adapter->pdev->dev, "UE Detected!!\n");
+ }
+
if (ue_status_lo) {
for (i = 0; ue_status_lo; ue_status_lo >>= 1, i++) {
if (ue_status_lo & 1)
@@ -1821,10 +1807,8 @@ static void be_worker(struct work_struct *work)
adapter->rx_post_starved = false;
be_post_rx_frags(adapter);
}
- if (!adapter->ue_detected) {
- if (be_detect_ue(adapter))
- be_dump_ue(adapter);
- }
+ if (!adapter->ue_detected)
+ be_detect_dump_ue(adapter);
schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH net-2.6 3/6] be2net: remove a BUG_ON in be_cmds.c
From: Ajit Khaparde @ 2010-08-22 9:25 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Async notifications other than link status are possible in certain
configurations. Remove the BUG_ON.
Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
---
drivers/net/benet/be_cmds.c | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
index 3d30549..22bd062 100644
--- a/drivers/net/benet/be_cmds.c
+++ b/drivers/net/benet/be_cmds.c
@@ -140,10 +140,8 @@ int be_process_mcc(struct be_adapter *adapter, int *status)
while ((compl = be_mcc_compl_get(adapter))) {
if (compl->flags & CQE_FLAGS_ASYNC_MASK) {
/* Interpret flags as an async trailer */
- BUG_ON(!is_link_state_evt(compl->flags));
-
- /* Interpret compl as a async link evt */
- be_async_link_state_process(adapter,
+ if (is_link_state_evt(compl->flags))
+ be_async_link_state_process(adapter,
(struct be_async_event_link_state *) compl);
} else if (compl->flags & CQE_FLAGS_COMPLETED_MASK) {
*status = be_mcc_compl_process(adapter, compl);
--
1.7.0.4
^ permalink raw reply related
* [PATCH net-2.6 4/6] be2net: fix to dynamically generate MAC Address for VFs
From: Ajit Khaparde @ 2010-08-22 9:26 UTC (permalink / raw)
To: David Miller; +Cc: netdev
The BE ASIC/firmware doesnot reserve and assign MAC address for VFs.
This results in the VF interfaces being created with MAC Address 0.
The code change proposed takes the MAC address of PF to generate a seed.
MAC Address for VFs are assigned incrementally starting from the seed.
These addresses are programmed in the ASIC by the PF and the VF driver
queries for the MAC address during its probe.
Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
---
drivers/net/benet/be.h | 14 +++++++++++
drivers/net/benet/be_main.c | 54 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 68 insertions(+), 0 deletions(-)
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
index 53306bf..4faf696 100644
--- a/drivers/net/benet/be.h
+++ b/drivers/net/benet/be.h
@@ -414,6 +414,20 @@ static inline void be_check_sriov_fn_type(struct be_adapter *adapter)
adapter->is_virtfn = (data != 0xAA);
}
+static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
+{
+ u32 addr;
+
+ addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0);
+
+ mac[5] = (u8)(addr & 0xFF);
+ mac[4] = (u8)((addr >> 8) & 0xFF);
+ mac[3] = (u8)((addr >> 16) & 0xFF);
+ mac[2] = 0xC9;
+ mac[1] = 0x00;
+ mac[0] = 0x00;
+}
+
extern void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped);
extern void be_link_status_update(struct be_adapter *adapter, bool link_up);
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 6eda7a0..949d9a1 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -2084,6 +2084,47 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
return status;
}
+/*
+ * Generate a seed MAC address from the PF MAC Address using jhash.
+ * MAC Address for VFs are assigned incrementally starting from the seed.
+ * These addresses are programmed in the ASIC by the PF and the VF driver
+ * queries for the MAC address during its probe.
+ */
+static inline int be_vf_eth_addr_config(struct be_adapter *adapter)
+{
+ u32 vf = 0;
+ int status;
+ u8 mac[ETH_ALEN];
+
+ be_vf_eth_addr_generate(adapter, mac);
+
+ for (vf = 0; vf < num_vfs; vf++) {
+ status = be_cmd_pmac_add(adapter, mac,
+ adapter->vf_cfg[vf].vf_if_handle,
+ &adapter->vf_cfg[vf].vf_pmac_id);
+ if (status)
+ dev_err(&adapter->pdev->dev,
+ "Mac address add failed for VF %d\n", vf);
+ else
+ memcpy(adapter->vf_cfg[vf].vf_mac_addr, mac, ETH_ALEN);
+
+ mac[5] += 1;
+ }
+ return status;
+}
+
+static inline void be_vf_eth_addr_rem(struct be_adapter *adapter)
+{
+ u32 vf;
+
+ for (vf = 0; vf < num_vfs; vf++) {
+ if (adapter->vf_cfg[vf].vf_pmac_id != BE_INVALID_PMAC_ID)
+ be_cmd_pmac_del(adapter,
+ adapter->vf_cfg[vf].vf_if_handle,
+ adapter->vf_cfg[vf].vf_pmac_id);
+ }
+}
+
static int be_setup(struct be_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
@@ -2143,10 +2184,20 @@ static int be_setup(struct be_adapter *adapter)
if (status != 0)
goto rx_qs_destroy;
+ if (be_physfn(adapter)) {
+ status = be_vf_eth_addr_config(adapter);
+ if (status)
+ goto mcc_q_destroy;
+ }
+
adapter->link_speed = -1;
return 0;
+mcc_q_destroy:
+ if (be_physfn(adapter))
+ be_vf_eth_addr_rem(adapter);
+ be_mcc_queues_destroy(adapter);
rx_qs_destroy:
be_rx_queues_destroy(adapter);
tx_qs_destroy:
@@ -2163,6 +2214,9 @@ do_none:
static int be_clear(struct be_adapter *adapter)
{
+ if (be_physfn(adapter))
+ be_vf_eth_addr_rem(adapter);
+
be_mcc_queues_destroy(adapter);
be_rx_queues_destroy(adapter);
be_tx_queues_destroy(adapter);
--
1.7.0.4
^ permalink raw reply related
* [PATCH net-2.6 5/6] be2net: stats for packets received due to internal switching in ASIC.
From: Ajit Khaparde @ 2010-08-22 9:27 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Counters for packets received due to internal switching are already available.
This change will start displaying them in ethtool -S
Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
---
drivers/net/benet/be_ethtool.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
index 13f0abb..d920634 100644
--- a/drivers/net/benet/be_ethtool.c
+++ b/drivers/net/benet/be_ethtool.c
@@ -91,6 +91,9 @@ static const struct be_ethtool_stat et_stats[] = {
{PORTSTAT_INFO(rx_non_rss_packets)},
{PORTSTAT_INFO(rx_ipv4_packets)},
{PORTSTAT_INFO(rx_ipv6_packets)},
+ {PORTSTAT_INFO(rx_switched_unicast_packets)},
+ {PORTSTAT_INFO(rx_switched_multicast_packets)},
+ {PORTSTAT_INFO(rx_switched_broadcast_packets)},
{PORTSTAT_INFO(tx_unicastframes)},
{PORTSTAT_INFO(tx_multicastframes)},
{PORTSTAT_INFO(tx_broadcastframes)},
--
1.7.0.4
^ permalink raw reply related
* [PATCH net-2.6 6/6] be2net: fix to get RxQ IDs 0 and 1.
From: Ajit Khaparde @ 2010-08-22 9:28 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Under certain configurations, it is possible to get RxQ IDs from
firmware which are not 0 and 1. This change ensures RxQ IDs 0 & 1
for the be2net network interfaces.
Signed-off-by: Somnath K<somnathk@serverengines.com>
Signed-off-by: Ajit Khaparde <ajitk@serverengines.com>
---
drivers/net/benet/be_main.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
index 949d9a1..f1b1454 100644
--- a/drivers/net/benet/be_main.c
+++ b/drivers/net/benet/be_main.c
@@ -2137,7 +2137,8 @@ static int be_setup(struct be_adapter *adapter)
if (be_physfn(adapter)) {
cap_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS |
BE_IF_FLAGS_PROMISCUOUS |
- BE_IF_FLAGS_PASS_L3L4_ERRORS;
+ BE_IF_FLAGS_PASS_L3L4_ERRORS |
+ BE_IF_FLAGS_RSS;
en_flags |= BE_IF_FLAGS_PASS_L3L4_ERRORS;
}
--
1.7.0.4
^ permalink raw reply related
* [PATCH net-2.6 0/6] be2net: some bug fixes for net-2.6
From: Ajit Khaparde @ 2010-08-22 9:29 UTC (permalink / raw)
To: David Miller; +Cc: netdev
Patchset includes bug fixes for net-2.6. Please apply.
1/5: fix net-snmp error because of wrong packet stats
2/6: fix a bug in UE detection logic
3/6: remove a BUG_ON in be_cmds.c
4/6: fix to dynamically generate MAC Address for VFs
5/6: display statistics for packets received due to internal switching in ASIC.
6/6: fix to get RxQ IDs 0 and 1.
Thanks
-Ajit
^ permalink raw reply
* [PATCH] net: use __be16 instead of u16 for the userspace code
From: Changli Gao @ 2010-08-22 11:09 UTC (permalink / raw)
To: David S. Miller; +Cc: netdev, Changli Gao
Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
include/linux/if_pppox.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index 1525b21..770e8fa 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -50,8 +50,8 @@ struct pppoe_addr {
* PPTP addressing definition
*/
struct pptp_addr {
- u16 call_id;
- struct in_addr sin_addr;
+ __be16 call_id;
+ struct in_addr sin_addr;
};
/************************************************************************
^ permalink raw reply related
* [PATCH] net: define __packed for the userspace code
From: Changli Gao @ 2010-08-22 11:12 UTC (permalink / raw)
To: David S. Miller; +Cc: Eric Dumazet, linux-kernel, netdev, Changli Gao
This commit
commit bc10502dba37d3b210efd9f3867212298f13b78e
Author: Eric Dumazet <eric.dumazet@gmail.com>
Date: Thu Jun 3 03:21:52 2010 -0700
net: use __packed annotation
makes use of __packed in the userspace code. So we'd better define __packed
for the userspace code too.
Signed-off-by: Changli Gao <xiaosuo@gmail.com>
---
include/linux/compiler.h | 4 ++++
include/linux/if_pppox.h | 4 ++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/include/linux/compiler.h b/include/linux/compiler.h
index c1a62c5..515b174 100644
--- a/include/linux/compiler.h
+++ b/include/linux/compiler.h
@@ -304,4 +304,8 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
*/
#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+#ifndef __packed
+# define __packed __attribute__((packed))
+#endif
+
#endif /* __LINUX_COMPILER_H */
^ permalink raw reply related
* Re: [PATCH] net: define __packed for the userspace code
From: Changli Gao @ 2010-08-22 11:23 UTC (permalink / raw)
To: David S. Miller; +Cc: Eric Dumazet, linux-kernel, netdev, Changli Gao
In-Reply-To: <1282475544-24708-1-git-send-email-xiaosuo@gmail.com>
On Sun, Aug 22, 2010 at 7:12 PM, Changli Gao <xiaosuo@gmail.com> wrote:
> This commit
>
> commit bc10502dba37d3b210efd9f3867212298f13b78e
> Author: Eric Dumazet <eric.dumazet@gmail.com>
> Date: Thu Jun 3 03:21:52 2010 -0700
>
> net: use __packed annotation
>
> makes use of __packed in the userspace code. So we'd better define __packed
> for the userspace code too.
>
Oh, sorry. This patch can't work as include/linux/compiler.h isn't
exported to the userspace. But where should we define __packed for the
userspace code? include/linux/types.h?
--
Regards,
Changli Gao(xiaosuo@gmail.com)
^ permalink raw reply
* [patch v1 00/12] IPVS: SIP Persistence Engine
From: Simon Horman @ 2010-08-22 12:44 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
This patch series adds load-balancing of UDP SIP based on Call-ID to
IPVS as well as a frame-work for extending IPVS to handle alternate
persistence requirements.
REVISIONS
This is "patch v1" of this series, which addresses a few minor problems, as
annotated on a per-patch basis, since the initial "rfc" posting. Internally
there were 4 rfc versions, 0.1, 0.2, 0.3 and 0.4, some of the notes for
some of the patches reflect those versions.
OVERVIEW
The approach that I have taken is what I call persistence engines.
The basic idea being that you can provide a module to LVS that alters
the way that it handles connection templates, which are at the core
of persistence. In particular, an additional key can be added, and
any of the normal IP address, port and protocol information can either
be used or ignored.
In the case of the SIP persistence engine, the only persistence engine, all
the keys used by the default persistence behaviour are used and the callid
is added as an extra key. I originally intended to ignore the cip, but this
can optionally be done by setting the persistence mask (-M) to 0.0.0.0
while allowing the flexibility of other mask values.
It is envisaged that the SIP persistence engine will be used in conjunction
with one-packet scheduling. I'm interested to hear if that doesn't fit your
needs.
CONFIGURATION
A persistence engine is associated with a virtual service
(as are schedulers). I have added the --pe option to the
ivpsadm -A and -E commands to allow the persistence engine
of a virtual service to be added, changed, or deleted.
e.g. ipvsadm -A -u 10.4.3.192:5060 -p 60 -M 0.0.0.0 -o --pe sip
There are no other configuration parameters at this time.
RUNNING
When a connection template is created, if its virtual service
has a persistence engine, then the persistence engine can add
an extra key to the connection template. For the SIP module this
is the callid. More generically, it is known as "pe data". And
both the name of the persistence engine, "pe name", and "pe data"
can be viewed in /proc/net/ip_vs_conn and by passing the
--persistent-conn option to ipvsadm -Lc.
e.g.
# ipvsadm -Lcn --persistent-conn
UDP 00:38 UDP 10.4.3.0:0 10.4.3.192:5060 127.0.0.1:5060 sip 193373839
Here we see a single persistence template (cport is 0), which has been
handled by the sip persistence engine. The pe data (callid) is 193373839.
In the case where the persistence engine can't match a packet for some
reason, the connection will fall back to the normal persistence handling.
This seems reasonable, as that if the packet ought to be dropped, iptables
could be used.
A limited amount of debugging information has been added which
can be enabled using a value of 9 or greater in
/proc/sys/net/ipv4/vs/debug_level
CODE AVAILABILITY
The kernel patches (13) are available in git as the pe-0.4 branch of
git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-test-2.6.git
The ipvsadm patches (2) are available in git as the pe-0.4 branch of
git://github.com/horms/ipvsadm-test.git
I will post the ipvsadm patches separately
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [patch v1 01/12] netfilter: nf_conntrack_sip: Allow ct_sip_get_header() to be called with a null ct argument
From: Simon Horman @ 2010-08-22 12:44 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
[-- Attachment #1: ct_sip_get_header-ct-null.patch --]
[-- Type: text/plain, Size: 683 bytes --]
Signed-off-by: Simon Horman <horms@verge.net.au>
---
The motivation for this is to allow ct_sip_get_header() to be
used by LVS without connection tracking as per subsequent patches.
Index: nf-next-2.6/net/netfilter/nf_conntrack_sip.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/nf_conntrack_sip.c 2010-07-14 20:40:40.000000000 +0900
+++ nf-next-2.6/net/netfilter/nf_conntrack_sip.c 2010-07-14 21:15:06.000000000 +0900
@@ -152,6 +152,9 @@ static int parse_addr(const struct nf_co
const char *end;
int ret = 0;
+ if (!ct)
+ return 0;
+
memset(addr, 0, sizeof(*addr));
switch (nf_ct_l3num(ct)) {
case AF_INET:
^ permalink raw reply
* [patch v1 02/12] netfilter: nf_conntrack_sip: Add callid parser
From: Simon Horman @ 2010-08-22 12:44 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
[-- Attachment #1: ct_sip_get_header-callid.patch --]
[-- Type: text/plain, Size: 2601 bytes --]
Signed-off-by: Simon Horman <horms@verge.net.au>
---
The motivation for this is for it to be used by LVS as per
subsequent patches.
* Patrick McHardy suggested changing word_len to check for the
next newline or whitespace. But I believe this is incorrect.
For example '#' would be permitted but it is invalid
in a word according to RFC3261.
Index: nf-next-2.6/net/netfilter/nf_conntrack_sip.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/nf_conntrack_sip.c 2010-07-24 21:02:05.000000000 +0900
+++ nf-next-2.6/net/netfilter/nf_conntrack_sip.c 2010-07-25 15:48:53.000000000 +0900
@@ -130,6 +130,44 @@ static int digits_len(const struct nf_co
return len;
}
+static int iswordc(const char c)
+{
+ if (isalnum(c) || c == '!' || c == '"' || c == '%' ||
+ (c >= '(' && c <= '/') || c == ':' || c == '<' || c == '>' ||
+ c == '?' || (c >= '[' && c <= ']') || c == '_' || c == '`' ||
+ c == '{' || c == '}' || c == '~')
+ return 1;
+ return 0;
+}
+
+static int word_len(const char *dptr, const char *limit)
+{
+ int len = 0;
+ while (dptr < limit && iswordc(*dptr)) {
+ dptr++;
+ len++;
+ }
+ return len;
+}
+
+static int callid_len(const struct nf_conn *ct, const char *dptr,
+ const char *limit, int *shift)
+{
+ int len, domain_len;
+
+ len = word_len(dptr, limit);
+ dptr += len;
+ if (!len || dptr == limit || *dptr != '@')
+ return len;
+ dptr++;
+ len++;
+
+ domain_len = word_len(dptr, limit);
+ if (!domain_len)
+ return 0;
+ return len + domain_len;
+}
+
/* get media type + port length */
static int media_len(const struct nf_conn *ct, const char *dptr,
const char *limit, int *shift)
@@ -299,6 +337,7 @@ static const struct sip_header ct_sip_hd
[SIP_HDR_VIA_TCP] = SIP_HDR("Via", "v", "TCP ", epaddr_len),
[SIP_HDR_EXPIRES] = SIP_HDR("Expires", NULL, NULL, digits_len),
[SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len),
+ [SIP_HDR_CALL_ID] = SIP_HDR("Call-Id", "i", NULL, callid_len),
};
static const char *sip_follow_continuation(const char *dptr, const char *limit)
Index: nf-next-2.6/include/linux/netfilter/nf_conntrack_sip.h
===================================================================
--- nf-next-2.6.orig/include/linux/netfilter/nf_conntrack_sip.h 2010-07-20 10:24:21.000000000 +0900
+++ nf-next-2.6/include/linux/netfilter/nf_conntrack_sip.h 2010-07-24 21:02:08.000000000 +0900
@@ -89,6 +89,7 @@ enum sip_header_types {
SIP_HDR_VIA_TCP,
SIP_HDR_EXPIRES,
SIP_HDR_CONTENT_LENGTH,
+ SIP_HDR_CALL_ID,
};
enum sdp_header_types {
^ permalink raw reply
* [patch v1 03/12] IPVS: compact ip_vs_sched_persist()
From: Simon Horman @ 2010-08-22 12:45 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
[-- Attachment #1: ip_vs_sched_persist-compact.patch --]
[-- Type: text/plain, Size: 5504 bytes --]
Compact ip_vs_sched_persist() by setting up parameters
and calling functions once.
Signed-off-by: Simon Horman <horms@verge.net.au>
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_core.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_core.c 2010-07-25 20:17:58.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_core.c 2010-07-25 20:18:21.000000000 +0900
@@ -192,10 +192,15 @@ ip_vs_sched_persist(struct ip_vs_service
struct ip_vs_iphdr iph;
struct ip_vs_dest *dest;
struct ip_vs_conn *ct;
- __be16 dport; /* destination port to forward */
+ __be16 dport = 0;
__be16 flags;
union nf_inet_addr snet; /* source network of the client,
after masking */
+ int protocol = iph.protocol;
+ const union nf_inet_addr *vaddr = &iph.daddr;
+ union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) };
+ __be16 vport = 0;
+
ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
@@ -226,119 +231,58 @@ ip_vs_sched_persist(struct ip_vs_service
* 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(svc->af, iph.protocol, &snet, 0,
- &iph.daddr, ports[1]);
- else
- ct = ip_vs_ct_in_get(svc->af, iph.protocol, &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 (ports[1] == svc->port) {
+ /* non-FTP template:
+ * <protocol, caddr, 0, vaddr, vport, daddr, dport>
+ * FTP template:
+ * <protocol, caddr, 0, vaddr, 0, daddr, 0>
*/
if (svc->port != FTPPORT)
- ct = ip_vs_conn_new(svc->af, iph.protocol,
- &snet, 0,
- &iph.daddr,
- ports[1],
- &dest->addr, dest->port,
- IP_VS_CONN_F_TEMPLATE,
- dest);
- else
- ct = ip_vs_conn_new(svc->af, iph.protocol,
- &snet, 0,
- &iph.daddr, 0,
- &dest->addr, 0,
- IP_VS_CONN_F_TEMPLATE,
- dest);
- if (ct == NULL)
- return NULL;
-
- ct->timeout = svc->timeout;
+ vport = ports[1];
} 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) {
- union nf_inet_addr fwmark = {
- .ip = htonl(svc->fwmark)
- };
-
- ct = ip_vs_ct_in_get(svc->af, IPPROTO_IP, &snet, 0,
- &fwmark, 0);
- } else
- ct = ip_vs_ct_in_get(svc->af, iph.protocol, &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.
+ /* 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->port)
- return NULL;
-
- dest = svc->scheduler->schedule(svc, skb);
- if (dest == NULL) {
- IP_VS_DBG(1, "p-schedule: no dest found.\n");
- return NULL;
+ if (svc->fwmark) {
+ protocol = IPPROTO_IP;
+ vaddr = &fwmark;
}
+ }
+ }
- /*
- * Create a template according to the service
- */
- if (svc->fwmark) {
- union nf_inet_addr fwmark = {
- .ip = htonl(svc->fwmark)
- };
-
- ct = ip_vs_conn_new(svc->af, IPPROTO_IP,
- &snet, 0,
- &fwmark, 0,
- &dest->addr, 0,
- IP_VS_CONN_F_TEMPLATE,
- dest);
- } else
- ct = ip_vs_conn_new(svc->af, iph.protocol,
- &snet, 0,
- &iph.daddr, 0,
- &dest->addr, 0,
- IP_VS_CONN_F_TEMPLATE,
- dest);
- if (ct == NULL)
- return NULL;
+ /* Check if a template already exists */
+ ct = ip_vs_ct_in_get(svc->af, protocol, &snet, 0, vaddr, vport);
- ct->timeout = svc->timeout;
- } else {
- /* set destination with the found template */
- dest = ct->dest;
+ 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) {
+ IP_VS_DBG(1, "p-schedule: no dest found.\n");
+ return NULL;
}
- dport = ports[1];
- }
+
+ if (ports[1] == svc->port && svc->port != FTPPORT)
+ dport = dest->port;
+
+ /* Create a template */
+ ct = ip_vs_conn_new(svc->af, protocol, &snet, 0,vaddr, vport,
+ &dest->addr, dport,
+ 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;
flags = (svc->flags & IP_VS_SVC_F_ONEPACKET
&& iph.protocol == IPPROTO_UDP)?
^ permalink raw reply
* [patch v1 04/12] IPVS: Add struct ip_vs_conn_param
From: Simon Horman @ 2010-08-22 12:45 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
[-- Attachment #1: ip_vs_conn_param.patch --]
[-- Type: text/plain, Size: 24613 bytes --]
Signed-off-by: Simon Horman <horms@verge.net.au>
---
The motivation for this is to allow persistence engine modules to
fill in the parameters.
v0.3: Add missing changes to ip_vs_ftp.c
v0.1: Initial release
Index: nf-next-2.6/include/net/ip_vs.h
===================================================================
--- nf-next-2.6.orig/include/net/ip_vs.h 2010-07-28 22:02:23.000000000 +0900
+++ nf-next-2.6/include/net/ip_vs.h 2010-07-28 22:02:26.000000000 +0900
@@ -355,6 +355,15 @@ struct ip_vs_protocol {
extern struct ip_vs_protocol * ip_vs_proto_get(unsigned short proto);
+struct ip_vs_conn_param {
+ const union nf_inet_addr *caddr;
+ const union nf_inet_addr *vaddr;
+ __be16 cport;
+ __be16 vport;
+ __u16 protocol;
+ u16 af;
+};
+
/*
* IP_VS structure allocated for each dynamically scheduled connection
*/
@@ -624,13 +633,23 @@ enum {
IP_VS_DIR_LAST,
};
-extern struct ip_vs_conn *ip_vs_conn_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port);
-
-extern struct ip_vs_conn *ip_vs_ct_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port);
+static inline void ip_vs_conn_fill_param(int af, int protocol,
+ const union nf_inet_addr *caddr,
+ __be16 cport,
+ const union nf_inet_addr *vaddr,
+ __be16 vport,
+ struct ip_vs_conn_param *p)
+{
+ p->af = af;
+ p->protocol = protocol;
+ p->caddr = caddr;
+ p->cport = cport;
+ p->vaddr = vaddr;
+ p->vport = vport;
+}
+
+struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p);
+struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p);
struct ip_vs_conn * ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
struct ip_vs_protocol *pp,
@@ -638,9 +657,7 @@ struct ip_vs_conn * ip_vs_conn_in_get_pr
unsigned int proto_off,
int inverse);
-extern struct ip_vs_conn *ip_vs_conn_out_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port);
+struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p);
struct ip_vs_conn * ip_vs_conn_out_get_proto(int af, const struct sk_buff *skb,
struct ip_vs_protocol *pp,
@@ -656,11 +673,10 @@ static inline void __ip_vs_conn_put(stru
extern void ip_vs_conn_put(struct ip_vs_conn *cp);
extern void ip_vs_conn_fill_cport(struct ip_vs_conn *cp, __be16 cport);
-extern struct ip_vs_conn *
-ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
- const union nf_inet_addr *vaddr, __be16 vport,
- const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
- struct ip_vs_dest *dest);
+struct ip_vs_conn *ip_vs_conn_new(const struct ip_vs_conn_param *p,
+ const union nf_inet_addr *daddr,
+ __be16 dport, unsigned flags,
+ struct ip_vs_dest *dest);
extern void ip_vs_conn_expire_now(struct ip_vs_conn *cp);
extern const char * ip_vs_state_name(__u16 proto, int state);
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_core.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_core.c 2010-07-28 22:02:23.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_core.c 2010-07-28 22:02:26.000000000 +0900
@@ -196,11 +196,7 @@ ip_vs_sched_persist(struct ip_vs_service
__be16 flags;
union nf_inet_addr snet; /* source network of the client,
after masking */
- int protocol = iph.protocol;
- const union nf_inet_addr *vaddr = &iph.daddr;
- union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) };
- __be16 vport = 0;
-
+ struct ip_vs_conn_param param;
ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph);
@@ -232,6 +228,11 @@ ip_vs_sched_persist(struct ip_vs_service
* is created for other persistent services.
*/
{
+ int protocol = iph.protocol;
+ const union nf_inet_addr *vaddr = &iph.daddr;
+ union nf_inet_addr fwmark = { .ip = htonl(svc->fwmark) };
+ __be16 vport = 0;
+
if (ports[1] == svc->port) {
/* non-FTP template:
* <protocol, caddr, 0, vaddr, vport, daddr, dport>
@@ -253,11 +254,12 @@ ip_vs_sched_persist(struct ip_vs_service
vaddr = &fwmark;
}
}
+ ip_vs_conn_fill_param(svc->af, protocol, &snet, 0,
+ vaddr, vport, ¶m);
}
/* Check if a template already exists */
- ct = ip_vs_ct_in_get(svc->af, protocol, &snet, 0, vaddr, vport);
-
+ ct = ip_vs_ct_in_get(¶m);
if (!ct || !ip_vs_check_template(ct)) {
/* No template found or the dest of the connection
* template is not available.
@@ -272,8 +274,7 @@ ip_vs_sched_persist(struct ip_vs_service
dport = dest->port;
/* Create a template */
- ct = ip_vs_conn_new(svc->af, protocol, &snet, 0,vaddr, vport,
- &dest->addr, dport,
+ ct = ip_vs_conn_new(¶m, &dest->addr, dport,
IP_VS_CONN_F_TEMPLATE, dest);
if (ct == NULL)
return NULL;
@@ -291,12 +292,7 @@ ip_vs_sched_persist(struct ip_vs_service
/*
* Create a new connection according to the template
*/
- cp = ip_vs_conn_new(svc->af, iph.protocol,
- &iph.saddr, ports[0],
- &iph.daddr, ports[1],
- &dest->addr, dport,
- flags,
- dest);
+ cp = ip_vs_conn_new(¶m, &dest->addr, dport, flags, dest);
if (cp == NULL) {
ip_vs_conn_put(ct);
return NULL;
@@ -362,14 +358,16 @@ ip_vs_schedule(struct ip_vs_service *svc
/*
* Create a connection entry.
*/
- cp = ip_vs_conn_new(svc->af, iph.protocol,
- &iph.saddr, pptr[0],
- &iph.daddr, pptr[1],
- &dest->addr, dest->port ? dest->port : pptr[1],
- flags,
- dest);
- if (cp == NULL)
- return NULL;
+ {
+ struct ip_vs_conn_param p;
+ ip_vs_conn_fill_param(svc->af, iph.protocol, &iph.saddr,
+ pptr[0], &iph.daddr, pptr[1], &p);
+ cp = ip_vs_conn_new(&p, &dest->addr,
+ dest->port ? dest->port : pptr[1],
+ flags, dest);
+ if (!cp)
+ return NULL;
+ }
IP_VS_DBG_BUF(6, "Schedule fwd:%c c:%s:%u v:%s:%u "
"d:%s:%u conn->flags:%X conn->refcnt:%d\n",
@@ -425,14 +423,17 @@ int ip_vs_leave(struct ip_vs_service *sv
/* create a new connection entry */
IP_VS_DBG(6, "%s(): create a cache_bypass entry\n", __func__);
- cp = ip_vs_conn_new(svc->af, iph.protocol,
- &iph.saddr, pptr[0],
- &iph.daddr, pptr[1],
- &daddr, 0,
- IP_VS_CONN_F_BYPASS | flags,
- NULL);
- if (cp == NULL)
- return NF_DROP;
+ {
+ struct ip_vs_conn_param p;
+ ip_vs_conn_fill_param(svc->af, iph.protocol,
+ &iph.saddr, pptr[0],
+ &iph.daddr, pptr[1], &p);
+ cp = ip_vs_conn_new(&p, &daddr, 0,
+ IP_VS_CONN_F_BYPASS | flags,
+ NULL);
+ if (!cp)
+ return NF_DROP;
+ }
/* statistics */
ip_vs_in_stats(cp, skb);
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_conn.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_conn.c 2010-07-28 22:02:23.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_conn.c 2010-07-28 22:02:26.000000000 +0900
@@ -218,27 +218,26 @@ static inline int ip_vs_conn_unhash(stru
/*
* Gets ip_vs_conn associated with supplied parameters in the ip_vs_conn_tab.
* Called for pkts coming from OUTside-to-INside.
- * s_addr, s_port: pkt source address (foreign host)
- * d_addr, d_port: pkt dest address (load balancer)
+ * p->caddr, p->cport: pkt source address (foreign host)
+ * p->vaddr, p->vport: pkt dest address (load balancer)
*/
-static inline struct ip_vs_conn *__ip_vs_conn_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+static inline struct ip_vs_conn *
+__ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
{
unsigned hash;
struct ip_vs_conn *cp;
- hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
+ hash = ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
ct_read_lock(hash);
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
- if (cp->af == af &&
- ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
- ip_vs_addr_equal(af, d_addr, &cp->vaddr) &&
- s_port == cp->cport && d_port == cp->vport &&
- ((!s_port) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
- protocol == cp->protocol) {
+ if (cp->af == p->af &&
+ ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
+ ip_vs_addr_equal(p->af, p->vaddr, &cp->vaddr) &&
+ p->cport == cp->cport && p->vport == cp->vport &&
+ ((!p->cport) ^ (!(cp->flags & IP_VS_CONN_F_NO_CPORT))) &&
+ p->protocol == cp->protocol) {
/* HIT */
atomic_inc(&cp->refcnt);
ct_read_unlock(hash);
@@ -251,71 +250,82 @@ static inline struct ip_vs_conn *__ip_vs
return NULL;
}
-struct ip_vs_conn *ip_vs_conn_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p)
{
struct ip_vs_conn *cp;
- cp = __ip_vs_conn_in_get(af, protocol, s_addr, s_port, d_addr, d_port);
- if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt))
- cp = __ip_vs_conn_in_get(af, protocol, s_addr, 0, d_addr,
- d_port);
+ cp = __ip_vs_conn_in_get(p);
+ if (!cp && atomic_read(&ip_vs_conn_no_cport_cnt)) {
+ struct ip_vs_conn_param cport_zero_p = *p;
+ cport_zero_p.cport = 0;
+ cp = __ip_vs_conn_in_get(&cport_zero_p);
+ }
IP_VS_DBG_BUF(9, "lookup/in %s %s:%d->%s:%d %s\n",
- ip_vs_proto_name(protocol),
- IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
- IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+ ip_vs_proto_name(p->protocol),
+ IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
+ IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
cp ? "hit" : "not hit");
return cp;
}
+static int
+ip_vs_conn_fill_param_proto(int af, const struct sk_buff *skb,
+ const struct ip_vs_iphdr *iph,
+ unsigned int proto_off, int inverse,
+ struct ip_vs_conn_param *p)
+{
+ __be16 _ports[2], *pptr;
+
+ pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
+ if (pptr == NULL)
+ return 1;
+
+ if (likely(!inverse))
+ ip_vs_conn_fill_param(af, iph->protocol, &iph->saddr, pptr[0],
+ &iph->daddr, pptr[1], p);
+ else
+ ip_vs_conn_fill_param(af, iph->protocol, &iph->saddr, pptr[0],
+ &iph->daddr, pptr[1], p);
+ return 0;
+}
+
struct ip_vs_conn *
ip_vs_conn_in_get_proto(int af, const struct sk_buff *skb,
struct ip_vs_protocol *pp,
const struct ip_vs_iphdr *iph,
unsigned int proto_off, int inverse)
{
- __be16 _ports[2], *pptr;
+ struct ip_vs_conn_param p;
- pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
- if (pptr == NULL)
+ if (ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p))
return NULL;
- if (likely(!inverse))
- return ip_vs_conn_in_get(af, iph->protocol,
- &iph->saddr, pptr[0],
- &iph->daddr, pptr[1]);
- else
- return ip_vs_conn_in_get(af, iph->protocol,
- &iph->daddr, pptr[1],
- &iph->saddr, pptr[0]);
+ return ip_vs_conn_in_get(&p);
}
EXPORT_SYMBOL_GPL(ip_vs_conn_in_get_proto);
/* Get reference to connection template */
-struct ip_vs_conn *ip_vs_ct_in_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+struct ip_vs_conn *ip_vs_ct_in_get(const struct ip_vs_conn_param *p)
{
unsigned hash;
struct ip_vs_conn *cp;
- hash = ip_vs_conn_hashkey(af, protocol, s_addr, s_port);
+ hash = ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
ct_read_lock(hash);
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
- if (cp->af == af &&
- ip_vs_addr_equal(af, s_addr, &cp->caddr) &&
+ if (cp->af == p->af &&
+ ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
/* protocol should only be IPPROTO_IP if
- * d_addr is a fwmark */
- ip_vs_addr_equal(protocol == IPPROTO_IP ? AF_UNSPEC : af,
- d_addr, &cp->vaddr) &&
- s_port == cp->cport && d_port == cp->vport &&
+ * p->vaddr is a fwmark */
+ ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC :
+ p->af, p->vaddr, &cp->vaddr) &&
+ p->cport == cp->cport && p->vport == cp->vport &&
cp->flags & IP_VS_CONN_F_TEMPLATE &&
- protocol == cp->protocol) {
+ p->protocol == cp->protocol) {
/* HIT */
atomic_inc(&cp->refcnt);
goto out;
@@ -327,9 +337,9 @@ struct ip_vs_conn *ip_vs_ct_in_get
ct_read_unlock(hash);
IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s\n",
- ip_vs_proto_name(protocol),
- IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
- IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+ ip_vs_proto_name(p->protocol),
+ IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
+ IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
cp ? "hit" : "not hit");
return cp;
@@ -341,9 +351,7 @@ struct ip_vs_conn *ip_vs_ct_in_get
* s_addr, s_port: pkt source address (inside host)
* d_addr, d_port: pkt dest address (foreign host)
*/
-struct ip_vs_conn *ip_vs_conn_out_get
-(int af, int protocol, const union nf_inet_addr *s_addr, __be16 s_port,
- const union nf_inet_addr *d_addr, __be16 d_port)
+struct ip_vs_conn *ip_vs_conn_out_get(const struct ip_vs_conn_param *p)
{
unsigned hash;
struct ip_vs_conn *cp, *ret=NULL;
@@ -351,16 +359,16 @@ struct ip_vs_conn *ip_vs_conn_out_get
/*
* Check for "full" addressed entries
*/
- hash = ip_vs_conn_hashkey(af, protocol, d_addr, d_port);
+ hash = ip_vs_conn_hashkey(p->af, p->protocol, p->vaddr, p->vport);
ct_read_lock(hash);
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
- if (cp->af == af &&
- ip_vs_addr_equal(af, d_addr, &cp->caddr) &&
- ip_vs_addr_equal(af, s_addr, &cp->daddr) &&
- d_port == cp->cport && s_port == cp->dport &&
- protocol == cp->protocol) {
+ if (cp->af == p->af &&
+ ip_vs_addr_equal(p->af, p->vaddr, &cp->caddr) &&
+ ip_vs_addr_equal(p->af, p->caddr, &cp->daddr) &&
+ p->vport == cp->cport && p->cport == cp->dport &&
+ p->protocol == cp->protocol) {
/* HIT */
atomic_inc(&cp->refcnt);
ret = cp;
@@ -371,9 +379,9 @@ struct ip_vs_conn *ip_vs_conn_out_get
ct_read_unlock(hash);
IP_VS_DBG_BUF(9, "lookup/out %s %s:%d->%s:%d %s\n",
- ip_vs_proto_name(protocol),
- IP_VS_DBG_ADDR(af, s_addr), ntohs(s_port),
- IP_VS_DBG_ADDR(af, d_addr), ntohs(d_port),
+ ip_vs_proto_name(p->protocol),
+ IP_VS_DBG_ADDR(p->af, p->caddr), ntohs(p->cport),
+ IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
ret ? "hit" : "not hit");
return ret;
@@ -385,20 +393,12 @@ ip_vs_conn_out_get_proto(int af, const s
const struct ip_vs_iphdr *iph,
unsigned int proto_off, int inverse)
{
- __be16 _ports[2], *pptr;
+ struct ip_vs_conn_param p;
- pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
- if (pptr == NULL)
+ if (!ip_vs_conn_fill_param_proto(af, skb, iph, proto_off, inverse, &p))
return NULL;
- if (likely(!inverse))
- return ip_vs_conn_out_get(af, iph->protocol,
- &iph->saddr, pptr[0],
- &iph->daddr, pptr[1]);
- else
- return ip_vs_conn_out_get(af, iph->protocol,
- &iph->daddr, pptr[1],
- &iph->saddr, pptr[0]);
+ return ip_vs_conn_out_get(&p);
}
EXPORT_SYMBOL_GPL(ip_vs_conn_out_get_proto);
@@ -751,13 +751,12 @@ void ip_vs_conn_expire_now(struct ip_vs_
* Create a new connection entry and hash it into the ip_vs_conn_tab
*/
struct ip_vs_conn *
-ip_vs_conn_new(int af, int proto, const union nf_inet_addr *caddr, __be16 cport,
- const union nf_inet_addr *vaddr, __be16 vport,
+ip_vs_conn_new(const struct ip_vs_conn_param *p,
const union nf_inet_addr *daddr, __be16 dport, unsigned flags,
struct ip_vs_dest *dest)
{
struct ip_vs_conn *cp;
- struct ip_vs_protocol *pp = ip_vs_proto_get(proto);
+ struct ip_vs_protocol *pp = ip_vs_proto_get(p->protocol);
cp = kmem_cache_zalloc(ip_vs_conn_cachep, GFP_ATOMIC);
if (cp == NULL) {
@@ -767,14 +766,14 @@ ip_vs_conn_new(int af, int proto, const
INIT_LIST_HEAD(&cp->c_list);
setup_timer(&cp->timer, ip_vs_conn_expire, (unsigned long)cp);
- cp->af = af;
- cp->protocol = proto;
- ip_vs_addr_copy(af, &cp->caddr, caddr);
- cp->cport = cport;
- ip_vs_addr_copy(af, &cp->vaddr, vaddr);
- cp->vport = vport;
+ cp->af = p->af;
+ cp->protocol = p->protocol;
+ ip_vs_addr_copy(p->af, &cp->caddr, p->caddr);
+ cp->cport = p->cport;
+ ip_vs_addr_copy(p->af, &cp->vaddr, p->vaddr);
+ cp->vport = p->vport;
/* proto should only be IPPROTO_IP if d_addr is a fwmark */
- ip_vs_addr_copy(proto == IPPROTO_IP ? AF_UNSPEC : af,
+ ip_vs_addr_copy(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
&cp->daddr, daddr);
cp->dport = dport;
cp->flags = flags;
@@ -803,7 +802,7 @@ ip_vs_conn_new(int af, int proto, const
/* Bind its packet transmitter */
#ifdef CONFIG_IP_VS_IPV6
- if (af == AF_INET6)
+ if (p->af == AF_INET6)
ip_vs_bind_xmit_v6(cp);
else
#endif
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_sync.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_sync.c 2010-07-28 22:02:23.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_sync.c 2010-07-28 22:02:26.000000000 +0900
@@ -301,6 +301,7 @@ static void ip_vs_process_message(const
struct ip_vs_conn *cp;
struct ip_vs_protocol *pp;
struct ip_vs_dest *dest;
+ struct ip_vs_conn_param param;
char *p;
int i;
@@ -370,18 +371,17 @@ static void ip_vs_process_message(const
}
}
- if (!(flags & IP_VS_CONN_F_TEMPLATE))
- cp = ip_vs_conn_in_get(AF_INET, s->protocol,
- (union nf_inet_addr *)&s->caddr,
- s->cport,
- (union nf_inet_addr *)&s->vaddr,
- s->vport);
- else
- cp = ip_vs_ct_in_get(AF_INET, s->protocol,
- (union nf_inet_addr *)&s->caddr,
- s->cport,
- (union nf_inet_addr *)&s->vaddr,
- s->vport);
+ {
+ ip_vs_conn_fill_param(AF_INET, s->protocol,
+ (union nf_inet_addr *)&s->caddr,
+ s->cport,
+ (union nf_inet_addr *)&s->vaddr,
+ s->vport, ¶m);
+ if (!(flags & IP_VS_CONN_F_TEMPLATE))
+ cp = ip_vs_conn_in_get(¶m);
+ else
+ cp = ip_vs_ct_in_get(¶m);
+ }
if (!cp) {
/*
* Find the appropriate destination for the connection.
@@ -406,14 +406,9 @@ static void ip_vs_process_message(const
else
flags &= ~IP_VS_CONN_F_INACTIVE;
}
- cp = ip_vs_conn_new(AF_INET, s->protocol,
- (union nf_inet_addr *)&s->caddr,
- s->cport,
- (union nf_inet_addr *)&s->vaddr,
- s->vport,
+ cp = ip_vs_conn_new(¶m,
(union nf_inet_addr *)&s->daddr,
- s->dport,
- flags, dest);
+ s->dport, flags, dest);
if (dest)
atomic_dec(&dest->refcnt);
if (!cp) {
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_proto_ah_esp.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_proto_ah_esp.c 2010-07-28 22:02:23.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_proto_ah_esp.c 2010-07-28 22:02:26.000000000 +0900
@@ -40,6 +40,19 @@ struct isakmp_hdr {
#define PORT_ISAKMP 500
+static void
+ah_esp_conn_fill_param_proto(int af, const struct ip_vs_iphdr *iph,
+ int inverse, struct ip_vs_conn_param *p)
+{
+ if (likely(!inverse))
+ ip_vs_conn_fill_param(af, IPPROTO_UDP,
+ &iph->saddr, htons(PORT_ISAKMP),
+ &iph->daddr, htons(PORT_ISAKMP), p);
+ else
+ ip_vs_conn_fill_param(af, iph->protocol,
+ &iph->saddr, htons(PORT_ISAKMP),
+ &iph->daddr, htons(PORT_ISAKMP), p);
+}
static struct ip_vs_conn *
ah_esp_conn_in_get(int af, const struct sk_buff *skb, struct ip_vs_protocol *pp,
@@ -47,21 +60,10 @@ ah_esp_conn_in_get(int af, const struct
int inverse)
{
struct ip_vs_conn *cp;
+ struct ip_vs_conn_param p;
- if (likely(!inverse)) {
- cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
- &iph->saddr,
- htons(PORT_ISAKMP),
- &iph->daddr,
- htons(PORT_ISAKMP));
- } else {
- cp = ip_vs_conn_in_get(af, IPPROTO_UDP,
- &iph->daddr,
- htons(PORT_ISAKMP),
- &iph->saddr,
- htons(PORT_ISAKMP));
- }
-
+ ah_esp_conn_fill_param_proto(af, iph, inverse, &p);
+ cp = ip_vs_conn_in_get(&p);
if (!cp) {
/*
* We are not sure if the packet is from our
@@ -87,21 +89,10 @@ ah_esp_conn_out_get(int af, const struct
int inverse)
{
struct ip_vs_conn *cp;
+ struct ip_vs_conn_param p;
- if (likely(!inverse)) {
- cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
- &iph->saddr,
- htons(PORT_ISAKMP),
- &iph->daddr,
- htons(PORT_ISAKMP));
- } else {
- cp = ip_vs_conn_out_get(af, IPPROTO_UDP,
- &iph->daddr,
- htons(PORT_ISAKMP),
- &iph->saddr,
- htons(PORT_ISAKMP));
- }
-
+ ah_esp_conn_fill_param_proto(af, iph, inverse, &p);
+ cp = ip_vs_conn_out_get(&p);
if (!cp) {
IP_VS_DBG_BUF(12, "Unknown ISAKMP entry for inout packet "
"%s%s %s->%s\n",
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_ftp.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_ftp.c 2010-07-28 22:02:23.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_ftp.c 2010-07-28 22:02:31.000000000 +0900
@@ -156,6 +156,7 @@ ip_vs_expect_callback(struct nf_conn *ct
{
struct nf_conntrack_tuple *orig, new_reply;
struct ip_vs_conn *cp;
+ struct ip_vs_conn_param p;
if (exp->tuple.src.l3num != PF_INET)
return;
@@ -170,9 +171,11 @@ ip_vs_expect_callback(struct nf_conn *ct
/* RS->CLIENT */
orig = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
- cp = ip_vs_conn_out_get(exp->tuple.src.l3num, orig->dst.protonum,
- &orig->src.u3, orig->src.u.tcp.port,
- &orig->dst.u3, orig->dst.u.tcp.port);
+ ip_vs_conn_fill_param(exp->tuple.src.l3num, orig->dst.protonum,
+ &orig->src.u3, orig->src.u.tcp.port,
+ &orig->dst.u3, orig->dst.u.tcp.port, &p);
+
+ cp = ip_vs_conn_out_get(&p);
if (cp) {
/* Change reply CLIENT->RS to CLIENT->VS */
new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
@@ -192,9 +195,7 @@ ip_vs_expect_callback(struct nf_conn *ct
}
/* CLIENT->VS */
- cp = ip_vs_conn_in_get(exp->tuple.src.l3num, orig->dst.protonum,
- &orig->src.u3, orig->src.u.tcp.port,
- &orig->dst.u3, orig->dst.u.tcp.port);
+ cp = ip_vs_conn_in_get(&p);
if (cp) {
/* Change reply VS->CLIENT to RS->CLIENT */
new_reply = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
@@ -327,13 +328,18 @@ static int ip_vs_ftp_out(struct ip_vs_ap
/*
* Now update or create an connection entry for it
*/
- n_cp = ip_vs_conn_out_get(AF_INET, iph->protocol, &from, port,
- &cp->caddr, 0);
+ {
+ struct ip_vs_conn_param p;
+ ip_vs_conn_fill_param(AF_INET, iph->protocol,
+ &from, port, &cp->caddr, 0, &p);
+ n_cp = ip_vs_conn_out_get(&p);
+ }
if (!n_cp) {
- n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
- &cp->caddr, 0,
- &cp->vaddr, port,
- &from, port,
+ struct ip_vs_conn_param p;
+
+ ip_vs_conn_fill_param(AF_INET, IPPROTO_TCP, &cp->caddr,
+ 0, &cp->vaddr, port, &p);
+ n_cp = ip_vs_conn_new(&p, &from, port,
IP_VS_CONN_F_NO_CPORT,
cp->dest);
if (!n_cp)
@@ -479,21 +485,23 @@ static int ip_vs_ftp_in(struct ip_vs_app
ip_vs_proto_name(iph->protocol),
&to.ip, ntohs(port), &cp->vaddr.ip, 0);
- n_cp = ip_vs_conn_in_get(AF_INET, iph->protocol,
- &to, port,
- &cp->vaddr, htons(ntohs(cp->vport)-1));
- if (!n_cp) {
- n_cp = ip_vs_conn_new(AF_INET, IPPROTO_TCP,
- &to, port,
+ {
+ struct ip_vs_conn_param p;
+
+ ip_vs_conn_fill_param(AF_INET, iph->protocol, &to, port,
&cp->vaddr, htons(ntohs(cp->vport)-1),
- &cp->daddr, htons(ntohs(cp->dport)-1),
- 0,
- cp->dest);
- if (!n_cp)
- return 0;
+ &p);
+ n_cp = ip_vs_conn_in_get(&p);
+ if (!n_cp) {
+ n_cp = ip_vs_conn_new(&p, &cp->daddr,
+ htons(ntohs(cp->dport)-1),
+ 0, cp->dest);
+ if (!n_cp)
+ return 0;
- /* add its controller */
- ip_vs_control_add(n_cp, cp);
+ /* add its controller */
+ ip_vs_control_add(n_cp, cp);
+ }
}
ct = (struct nf_conn *)skb->nfct;
^ permalink raw reply
* [patch v1 05/12] IPVS: Allow null argument to ip_vs_scheduler_put()
From: Simon Horman @ 2010-08-22 12:45 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
[-- Attachment #1: ip_vs_scheduler_put-null-ok.patch --]
[-- Type: text/plain, Size: 2010 bytes --]
This simplifies caller logic sightly.
Signed-off-by: Simon Horman <horms@verge.net.au>
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_ctl.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_ctl.c 2010-07-22 21:52:23.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_ctl.c 2010-07-22 21:54:38.000000000 +0900
@@ -1167,7 +1167,7 @@ ip_vs_add_service(struct ip_vs_service_u
if (sched == NULL) {
pr_info("Scheduler module ip_vs_%s not found\n", u->sched_name);
ret = -ENOENT;
- goto out_mod_dec;
+ goto out_err;
}
#ifdef CONFIG_IP_VS_IPV6
@@ -1227,7 +1227,7 @@ ip_vs_add_service(struct ip_vs_service_u
*svc_p = svc;
return 0;
- out_err:
+ out_err:
if (svc != NULL) {
if (svc->scheduler)
ip_vs_unbind_scheduler(svc);
@@ -1240,7 +1240,6 @@ ip_vs_add_service(struct ip_vs_service_u
}
ip_vs_scheduler_put(sched);
- out_mod_dec:
/* decrease the module use count */
ip_vs_use_count_dec();
@@ -1323,10 +1322,7 @@ ip_vs_edit_service(struct ip_vs_service
#ifdef CONFIG_IP_VS_IPV6
out:
#endif
-
- if (old_sched)
- ip_vs_scheduler_put(old_sched);
-
+ ip_vs_scheduler_put(old_sched);
return ret;
}
@@ -1350,8 +1346,7 @@ static void __ip_vs_del_service(struct i
/* Unbind scheduler */
old_sched = svc->scheduler;
ip_vs_unbind_scheduler(svc);
- if (old_sched)
- ip_vs_scheduler_put(old_sched);
+ ip_vs_scheduler_put(old_sched);
/* Unbind app inc */
if (svc->inc) {
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_sched.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_sched.c 2010-07-22 21:52:23.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_sched.c 2010-07-22 21:55:42.000000000 +0900
@@ -159,7 +159,7 @@ struct ip_vs_scheduler *ip_vs_scheduler_
void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler)
{
- if (scheduler->module)
+ if (scheduler && scheduler->module)
module_put(scheduler->module);
}
^ permalink raw reply
* [patch v1 07/12] IPVS: Add struct ip_vs_pe
From: Simon Horman @ 2010-08-22 12:45 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
[-- Attachment #1: pe-struct.patch --]
[-- Type: text/plain, Size: 10105 bytes --]
Signed-off-by: Simon Horman <horms@verge.net.au>
---
This the first of several patches to add persistence engines.
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_conn.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_conn.c 2010-07-26 07:31:06.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_conn.c 2010-07-26 16:39:45.000000000 +0900
@@ -148,6 +148,29 @@ static unsigned int ip_vs_conn_hashkey(i
& ip_vs_conn_tab_mask;
}
+static unsigned int ip_vs_conn_hashkey_param(const struct ip_vs_conn_param *p)
+{
+ if (p->pe && p->pe->hashkey_raw)
+ return p->pe->hashkey_raw(p, ip_vs_conn_rnd) &
+ ip_vs_conn_tab_mask;
+ return ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
+}
+
+static unsigned int ip_vs_conn_hashkey_conn(const struct ip_vs_conn *cp)
+{
+ struct ip_vs_conn_param p;
+
+ ip_vs_conn_fill_param(cp->af, cp->protocol, &cp->caddr, cp->cport,
+ NULL, 0, &p);
+
+ if (cp->dest->svc->pe) {
+ p.pe = cp->dest->svc->pe;
+ p.pe_data = cp->pe_data;
+ p.pe_data_len = cp->pe_data_len;
+ }
+
+ return ip_vs_conn_hashkey_param(&p);
+}
/*
* Hashes ip_vs_conn in ip_vs_conn_tab by proto,addr,port.
@@ -162,7 +185,7 @@ static inline int ip_vs_conn_hash(struct
return 0;
/* Hash by protocol, client address and port */
- hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
+ hash = ip_vs_conn_hashkey_conn(cp);
ct_write_lock(hash);
spin_lock(&cp->lock);
@@ -195,7 +218,7 @@ static inline int ip_vs_conn_unhash(stru
int ret;
/* unhash it and decrease its reference counter */
- hash = ip_vs_conn_hashkey(cp->af, cp->protocol, &cp->caddr, cp->cport);
+ hash = ip_vs_conn_hashkey_conn(cp);
ct_write_lock(hash);
spin_lock(&cp->lock);
@@ -227,7 +250,7 @@ __ip_vs_conn_in_get(const struct ip_vs_c
unsigned hash;
struct ip_vs_conn *cp;
- hash = ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
+ hash = ip_vs_conn_hashkey_param(p);
ct_read_lock(hash);
@@ -312,11 +335,17 @@ struct ip_vs_conn *ip_vs_ct_in_get(const
unsigned hash;
struct ip_vs_conn *cp;
- hash = ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
+ hash = ip_vs_conn_hashkey_param(p);
ct_read_lock(hash);
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
+ if (p->pe && p->pe->ct_match) {
+ if (p->pe->ct_match(p, cp))
+ goto out;
+ continue;
+ }
+
if (cp->af == p->af &&
ip_vs_addr_equal(p->af, p->caddr, &cp->caddr) &&
/* protocol should only be IPPROTO_IP if
@@ -325,15 +354,14 @@ struct ip_vs_conn *ip_vs_ct_in_get(const
p->af, p->vaddr, &cp->vaddr) &&
p->cport == cp->cport && p->vport == cp->vport &&
cp->flags & IP_VS_CONN_F_TEMPLATE &&
- p->protocol == cp->protocol) {
- /* HIT */
- atomic_inc(&cp->refcnt);
+ p->protocol == cp->protocol)
goto out;
- }
}
cp = NULL;
out:
+ if (cp)
+ atomic_inc(&cp->refcnt);
ct_read_unlock(hash);
IP_VS_DBG_BUF(9, "template lookup/in %s %s:%d->%s:%d %s\n",
@@ -359,7 +387,7 @@ struct ip_vs_conn *ip_vs_conn_out_get(co
/*
* Check for "full" addressed entries
*/
- hash = ip_vs_conn_hashkey(p->af, p->protocol, p->vaddr, p->vport);
+ hash = ip_vs_conn_hashkey_param(p);
ct_read_lock(hash);
@@ -777,6 +805,10 @@ ip_vs_conn_new(const struct ip_vs_conn_p
&cp->daddr, daddr);
cp->dport = dport;
cp->flags = flags;
+ if (p->pe_data) {
+ cp->pe_data = p->pe_data;
+ cp->pe_data_len = p->pe_data_len;
+ }
spin_lock_init(&cp->lock);
/*
@@ -817,7 +849,6 @@ ip_vs_conn_new(const struct ip_vs_conn_p
return cp;
}
-
/*
* /proc/net/ip_vs_conn entries
*/
@@ -833,7 +864,7 @@ static void *ip_vs_conn_array(struct seq
list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
if (pos-- == 0) {
seq->private = &ip_vs_conn_tab[idx];
- return cp;
+ return cp;
}
}
ct_read_unlock_bh(idx);
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_core.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_core.c 2010-07-26 07:31:07.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_core.c 2010-07-26 16:39:38.000000000 +0900
@@ -175,6 +175,19 @@ ip_vs_set_state(struct ip_vs_conn *cp, i
return pp->state_transition(cp, direction, skb, pp);
}
+static inline int
+ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc,
+ struct sk_buff *skb, int protocol,
+ const union nf_inet_addr *caddr, __be16 cport,
+ const union nf_inet_addr *vaddr, __be16 vport,
+ struct ip_vs_conn_param *p)
+{
+ ip_vs_conn_fill_param(svc->af, protocol, caddr, cport, vaddr, vport, p);
+ p->pe = svc->pe;
+ if (p->pe && p->pe->fill_param)
+ return p->pe->fill_param(p, skb);
+ return 0;
+}
/*
* IPVS persistent scheduling function
@@ -185,7 +198,7 @@ ip_vs_set_state(struct ip_vs_conn *cp, i
*/
static struct ip_vs_conn *
ip_vs_sched_persist(struct ip_vs_service *svc,
- const struct sk_buff *skb,
+ struct sk_buff *skb,
__be16 ports[2])
{
struct ip_vs_conn *cp = NULL;
@@ -254,8 +267,9 @@ ip_vs_sched_persist(struct ip_vs_service
vaddr = &fwmark;
}
}
- ip_vs_conn_fill_param(svc->af, protocol, &snet, 0,
- vaddr, vport, ¶m);
+ if (ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0,
+ vaddr, vport, ¶m))
+ return NULL;
}
/* Check if a template already exists */
@@ -316,7 +330,7 @@ ip_vs_sched_persist(struct ip_vs_service
* Protocols supported: TCP, UDP
*/
struct ip_vs_conn *
-ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
+ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb)
{
struct ip_vs_conn *cp = NULL;
struct ip_vs_iphdr iph;
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_sync.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_sync.c 2010-07-26 07:31:06.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_sync.c 2010-07-26 07:31:15.000000000 +0900
@@ -288,6 +288,16 @@ void ip_vs_sync_conn(struct ip_vs_conn *
ip_vs_sync_conn(cp->control);
}
+static inline int
+ip_vs_conn_fill_param_sync(int af, int protocol,
+ const union nf_inet_addr *caddr, __be16 cport,
+ const union nf_inet_addr *vaddr, __be16 vport,
+ struct ip_vs_conn_param *p)
+{
+ /* XXX: Need to take into account persistence engine */
+ ip_vs_conn_fill_param(af, protocol, caddr, cport, vaddr, vport, p);
+ return 0;
+}
/*
* Process received multicast message and create the corresponding
@@ -372,11 +382,14 @@ static void ip_vs_process_message(const
}
{
- ip_vs_conn_fill_param(AF_INET, s->protocol,
+ if (ip_vs_conn_fill_param_sync(AF_INET, s->protocol,
(union nf_inet_addr *)&s->caddr,
s->cport,
(union nf_inet_addr *)&s->vaddr,
- s->vport, ¶m);
+ s->vport, ¶m)) {
+ pr_err("ip_vs_conn_fill_param_sync failed");
+ return;
+ }
if (!(flags & IP_VS_CONN_F_TEMPLATE))
cp = ip_vs_conn_in_get(¶m);
else
Index: nf-next-2.6/include/net/ip_vs.h
===================================================================
--- nf-next-2.6.orig/include/net/ip_vs.h 2010-07-26 07:31:07.000000000 +0900
+++ nf-next-2.6/include/net/ip_vs.h 2010-07-26 16:39:45.000000000 +0900
@@ -362,6 +362,10 @@ struct ip_vs_conn_param {
__be16 vport;
__u16 protocol;
u16 af;
+
+ const struct ip_vs_pe *pe;
+ char *pe_data;
+ __u8 pe_data_len;
};
/*
@@ -414,6 +418,9 @@ struct ip_vs_conn {
void *app_data; /* Application private data */
struct ip_vs_seq in_seq; /* incoming seq. struct */
struct ip_vs_seq out_seq; /* outgoing seq. struct */
+
+ char *pe_data;
+ __u8 pe_data_len;
};
@@ -484,6 +491,9 @@ struct ip_vs_service {
struct ip_vs_scheduler *scheduler; /* bound scheduler object */
rwlock_t sched_lock; /* lock sched_data */
void *sched_data; /* scheduler application data */
+
+ /* alternate persistence engine */
+ struct ip_vs_pe *pe;
};
@@ -547,6 +557,19 @@ struct ip_vs_scheduler {
const struct sk_buff *skb);
};
+/* The persistence engine object */
+struct ip_vs_pe {
+ struct list_head n_list; /* d-linked list head */
+ char *name; /* scheduler name */
+ atomic_t refcnt; /* reference counter */
+ struct module *module; /* THIS_MODULE/NULL */
+
+ /* get the connection template, if any */
+ int (*fill_param)(struct ip_vs_conn_param *p, struct sk_buff *skb);
+ bool (*ct_match)(const struct ip_vs_conn_param *p,
+ struct ip_vs_conn *ct);
+ u32 (*hashkey_raw)(const struct ip_vs_conn_param *p, u32 initval);
+};
/*
* The application module object (a.k.a. app incarnation)
@@ -646,6 +669,8 @@ static inline void ip_vs_conn_fill_param
p->cport = cport;
p->vaddr = vaddr;
p->vport = vport;
+ p->pe = NULL;
+ p->pe_data = NULL;
}
struct ip_vs_conn *ip_vs_conn_in_get(const struct ip_vs_conn_param *p);
@@ -801,7 +826,7 @@ extern int ip_vs_unbind_scheduler(struct
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);
+ip_vs_schedule(struct ip_vs_service *svc, struct sk_buff *skb);
extern int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
struct ip_vs_protocol *pp);
Index: nf-next-2.6/include/linux/ip_vs.h
===================================================================
--- nf-next-2.6.orig/include/linux/ip_vs.h 2010-07-26 07:32:01.000000000 +0900
+++ nf-next-2.6/include/linux/ip_vs.h 2010-07-26 16:39:38.000000000 +0900
@@ -89,8 +89,10 @@
#define IP_VS_CONN_F_ONE_PACKET 0x2000 /* forward only one packet */
#define IP_VS_SCHEDNAME_MAXLEN 16
+#define IP_VS_PENAME_MAXLEN 16
#define IP_VS_IFNAME_MAXLEN 16
+#define IP_VS_PEDATA_MAXLEN 255
/*
* The struct ip_vs_service_user and struct ip_vs_dest_user are
^ permalink raw reply
* [patch v1 09/12] IPVS: management of persistence engine modules
From: Simon Horman @ 2010-08-22 12:45 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
[-- Attachment #1: pe-framework.patch --]
[-- Type: text/plain, Size: 5610 bytes --]
This is based heavily on the scheduler management code
Signed-off-by: Simon Horman <horms@verge.net.au>
v1
* As suggested by Stephen Hemminger
- Convert __ip_vs_pe_lock from a rwlock to a spinlock.
This code isn't performance-critical, so there is no need for RCU.
- Rename __ip_vs_pe_lock as ip_vs_pe_lock
* Stephen also suggested open-coding ip_vs_{un,}bind_pe()
as they are very short. But I would prefer to keep them as they are used
along side ip_vs_{un,}bind_scheduler which are too long to be open-coded.
v0.4
* Export register_ip_vs_pe and unregister_ip_vs_pe
* Use one line comment format for one line comments.
* Only use at most one blank line consecutively
Index: lvs-test-2.6/include/net/ip_vs.h
===================================================================
--- lvs-test-2.6.orig/include/net/ip_vs.h 2010-08-22 21:31:05.000000000 +0900
+++ lvs-test-2.6/include/net/ip_vs.h 2010-08-22 21:31:57.000000000 +0900
@@ -793,6 +793,12 @@ extern int ip_vs_app_pkt_in(struct ip_vs
extern int ip_vs_app_init(void);
extern void ip_vs_app_cleanup(void);
+void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe);
+void ip_vs_unbind_pe(struct ip_vs_service *svc);
+int register_ip_vs_pe(struct ip_vs_pe *pe);
+int unregister_ip_vs_pe(struct ip_vs_pe *pe);
+extern struct ip_vs_pe *ip_vs_pe_get(const char *name);
+extern void ip_vs_pe_put(struct ip_vs_pe *pe);
/*
* IPVS protocol functions (from ip_vs_proto.c)
Index: lvs-test-2.6/net/netfilter/ipvs/Makefile
===================================================================
--- lvs-test-2.6.orig/net/netfilter/ipvs/Makefile 2010-08-22 21:31:05.000000000 +0900
+++ lvs-test-2.6/net/netfilter/ipvs/Makefile 2010-08-22 21:31:56.000000000 +0900
@@ -11,7 +11,7 @@ ip_vs_proto-objs-$(CONFIG_IP_VS_PROTO_SC
ip_vs-objs := ip_vs_conn.o ip_vs_core.o ip_vs_ctl.o ip_vs_sched.o \
ip_vs_xmit.o ip_vs_app.o ip_vs_sync.o \
- ip_vs_est.o ip_vs_proto.o \
+ ip_vs_est.o ip_vs_proto.o ip_vs_pe.o \
$(ip_vs_proto-objs-y)
Index: lvs-test-2.6/net/netfilter/ipvs/ip_vs_pe.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ lvs-test-2.6/net/netfilter/ipvs/ip_vs_pe.c 2010-08-22 21:31:56.000000000 +0900
@@ -0,0 +1,147 @@
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <asm/string.h>
+#include <linux/kmod.h>
+#include <linux/sysctl.h>
+
+#include <net/ip_vs.h>
+
+/* IPVS pe list */
+static LIST_HEAD(ip_vs_pe);
+
+/* lock for service table */
+static DEFINE_SPINLOCK(ip_vs_pe_lock);
+
+/* Bind a service with a pe */
+void ip_vs_bind_pe(struct ip_vs_service *svc, struct ip_vs_pe *pe)
+{
+ svc->pe = pe;
+}
+
+/* Unbind a service from its pe */
+void ip_vs_unbind_pe(struct ip_vs_service *svc)
+{
+ svc->pe = NULL;
+}
+
+/* Get pe in the pe list by name */
+static struct ip_vs_pe *
+ip_vs_pe_getbyname(const char *pe_name)
+{
+ struct ip_vs_pe *pe;
+
+ IP_VS_DBG(2, "%s(): pe_name \"%s\"\n", __func__,
+ pe_name);
+
+ spin_lock_bh(&ip_vs_pe_lock);
+
+ list_for_each_entry(pe, &ip_vs_pe, n_list) {
+ /* Test and get the modules atomically */
+ if (pe->module &&
+ !try_module_get(pe->module)) {
+ /* This pe is just deleted */
+ continue;
+ }
+ if (strcmp(pe_name, pe->name)==0) {
+ /* HIT */
+ spin_unlock_bh(&ip_vs_pe_lock);
+ return pe;
+ }
+ if (pe->module)
+ module_put(pe->module);
+ }
+
+ spin_unlock_bh(&ip_vs_pe_lock);
+ return NULL;
+}
+
+/* Lookup pe and try to load it if it doesn't exist */
+struct ip_vs_pe *ip_vs_pe_get(const char *name)
+{
+ struct ip_vs_pe *pe;
+
+ /* Search for the pe by name */
+ pe = ip_vs_pe_getbyname(name);
+
+ /* If pe not found, load the module and search again */
+ if (!pe) {
+ request_module("ip_vs_pe_%s", name);
+ pe = ip_vs_pe_getbyname(name);
+ }
+
+ return pe;
+}
+
+void ip_vs_pe_put(struct ip_vs_pe *pe)
+{
+ if (pe && pe->module)
+ module_put(pe->module);
+}
+
+/* Register a pe in the pe list */
+int register_ip_vs_pe(struct ip_vs_pe *pe)
+{
+ struct ip_vs_pe *tmp;
+
+ /* increase the module use count */
+ ip_vs_use_count_inc();
+
+ spin_lock_bh(&ip_vs_pe_lock);
+
+ if (!list_empty(&pe->n_list)) {
+ spin_unlock_bh(&ip_vs_pe_lock);
+ ip_vs_use_count_dec();
+ pr_err("%s(): [%s] pe already linked\n",
+ __func__, pe->name);
+ return -EINVAL;
+ }
+
+ /* Make sure that the pe with this name doesn't exist
+ * in the pe list.
+ */
+ list_for_each_entry(tmp, &ip_vs_pe, n_list) {
+ if (strcmp(tmp->name, pe->name) == 0) {
+ spin_unlock_bh(&ip_vs_pe_lock);
+ ip_vs_use_count_dec();
+ pr_err("%s(): [%s] pe already existed "
+ "in the system\n", __func__, pe->name);
+ return -EINVAL;
+ }
+ }
+ /* Add it into the d-linked pe list */
+ list_add(&pe->n_list, &ip_vs_pe);
+ spin_unlock_bh(&ip_vs_pe_lock);
+
+ pr_info("[%s] pe registered.\n", pe->name);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(register_ip_vs_pe);
+
+/* Unregister a pe from the pe list */
+int unregister_ip_vs_pe(struct ip_vs_pe *pe)
+{
+ spin_lock_bh(&ip_vs_pe_lock);
+ if (list_empty(&pe->n_list)) {
+ spin_unlock_bh(&ip_vs_pe_lock);
+ pr_err("%s(): [%s] pe is not in the list. failed\n",
+ __func__, pe->name);
+ return -EINVAL;
+ }
+
+ /* Remove it from the d-linked pe list */
+ list_del(&pe->n_list);
+ spin_unlock_bh(&ip_vs_pe_lock);
+
+ /* decrease the module use count */
+ ip_vs_use_count_dec();
+
+ pr_info("[%s] pe unregistered.\n", pe->name);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(unregister_ip_vs_pe);
^ permalink raw reply
* [patch v1 10/12] IPVS: Allow configuration of persistence engines
From: Simon Horman @ 2010-08-22 12:45 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
[-- Attachment #1: pe-ctl.patch --]
[-- Type: text/plain, Size: 5421 bytes --]
Allow the persistence engine of a virtual service to be set, edited
and unset.
This feature only works with the netlink user-space interface.
Signed-off-by: Simon Horman <horms@verge.net.au>
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_ctl.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_ctl.c 2010-07-27 06:20:20.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_ctl.c 2010-07-27 22:11:58.000000000 +0900
@@ -1157,6 +1157,7 @@ ip_vs_add_service(struct ip_vs_service_u
{
int ret = 0;
struct ip_vs_scheduler *sched = NULL;
+ struct ip_vs_pe *pe = NULL;
struct ip_vs_service *svc = NULL;
/* increase the module use count */
@@ -1170,6 +1171,16 @@ ip_vs_add_service(struct ip_vs_service_u
goto out_err;
}
+ if (u->pe_name && *u->pe_name) {
+ pe = ip_vs_pe_get(u->pe_name);
+ if (pe == NULL) {
+ pr_info("persistence engine module ip_vs_pe_%s "
+ "not found\n", u->pe_name);
+ ret = -ENOENT;
+ goto out_err;
+ }
+ }
+
#ifdef CONFIG_IP_VS_IPV6
if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) {
ret = -EINVAL;
@@ -1207,6 +1218,10 @@ ip_vs_add_service(struct ip_vs_service_u
goto out_err;
sched = NULL;
+ /* Bind the ct retriever */
+ ip_vs_bind_pe(svc, pe);
+ pe = NULL;
+
/* Update the virtual service counters */
if (svc->port == FTPPORT)
atomic_inc(&ip_vs_ftpsvc_counter);
@@ -1238,6 +1253,7 @@ ip_vs_add_service(struct ip_vs_service_u
kfree(svc);
}
ip_vs_scheduler_put(sched);
+ ip_vs_pe_put(pe);
/* decrease the module use count */
ip_vs_use_count_dec();
@@ -1253,6 +1269,7 @@ static int
ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u)
{
struct ip_vs_scheduler *sched, *old_sched;
+ struct ip_vs_pe *pe = NULL, *old_pe = NULL;
int ret = 0;
/*
@@ -1265,6 +1282,17 @@ ip_vs_edit_service(struct ip_vs_service
}
old_sched = sched;
+ if (u->pe_name && *u->pe_name) {
+ pe = ip_vs_pe_get(u->pe_name);
+ if (pe == NULL) {
+ pr_info("persistence engine module ip_vs_pe_%s "
+ "not found\n", u->pe_name);
+ ret = -ENOENT;
+ goto out;
+ }
+ old_pe = pe;
+ }
+
#ifdef CONFIG_IP_VS_IPV6
if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) {
ret = -EINVAL;
@@ -1316,12 +1344,17 @@ ip_vs_edit_service(struct ip_vs_service
}
}
+ old_pe = svc->pe;
+ if (pe != old_pe) {
+ ip_vs_unbind_pe(svc);
+ ip_vs_bind_pe(svc, pe);
+ }
+
out_unlock:
write_unlock_bh(&__ip_vs_svc_lock);
-#ifdef CONFIG_IP_VS_IPV6
out:
-#endif
ip_vs_scheduler_put(old_sched);
+ ip_vs_pe_put(old_pe);
return ret;
}
@@ -2553,6 +2586,8 @@ static const struct nla_policy ip_vs_svc
[IPVS_SVC_ATTR_FWMARK] = { .type = NLA_U32 },
[IPVS_SVC_ATTR_SCHED_NAME] = { .type = NLA_NUL_STRING,
.len = IP_VS_SCHEDNAME_MAXLEN },
+ [IPVS_SVC_ATTR_PE_NAME] = { .type = NLA_NUL_STRING,
+ .len = IP_VS_PENAME_MAXLEN },
[IPVS_SVC_ATTR_FLAGS] = { .type = NLA_BINARY,
.len = sizeof(struct ip_vs_flags) },
[IPVS_SVC_ATTR_TIMEOUT] = { .type = NLA_U32 },
@@ -2629,6 +2664,8 @@ static int ip_vs_genl_fill_service(struc
}
NLA_PUT_STRING(skb, IPVS_SVC_ATTR_SCHED_NAME, svc->scheduler->name);
+ if (svc->pe)
+ NLA_PUT_STRING(skb, IPVS_SVC_ATTR_PE_NAME, svc->pe->name);
NLA_PUT(skb, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags);
NLA_PUT_U32(skb, IPVS_SVC_ATTR_TIMEOUT, svc->timeout / HZ);
NLA_PUT_U32(skb, IPVS_SVC_ATTR_NETMASK, svc->netmask);
@@ -2746,12 +2783,13 @@ static int ip_vs_genl_parse_service(stru
/* If a full entry was requested, check for the additional fields */
if (full_entry) {
- struct nlattr *nla_sched, *nla_flags, *nla_timeout,
+ struct nlattr *nla_sched, *nla_pe, *nla_flags, *nla_timeout,
*nla_netmask;
struct ip_vs_flags flags;
struct ip_vs_service *svc;
nla_sched = attrs[IPVS_SVC_ATTR_SCHED_NAME];
+ nla_pe = attrs[IPVS_SVC_ATTR_PE_NAME];
nla_flags = attrs[IPVS_SVC_ATTR_FLAGS];
nla_timeout = attrs[IPVS_SVC_ATTR_TIMEOUT];
nla_netmask = attrs[IPVS_SVC_ATTR_NETMASK];
@@ -2777,6 +2815,7 @@ static int ip_vs_genl_parse_service(stru
usvc->flags = (usvc->flags & ~flags.mask) |
(flags.flags & flags.mask);
usvc->sched_name = nla_data(nla_sched);
+ usvc->pe_name = nla_pe ? nla_data(nla_pe) : NULL;
usvc->timeout = nla_get_u32(nla_timeout);
usvc->netmask = nla_get_u32(nla_netmask);
}
Index: nf-next-2.6/include/linux/ip_vs.h
===================================================================
--- nf-next-2.6.orig/include/linux/ip_vs.h 2010-07-27 06:20:20.000000000 +0900
+++ nf-next-2.6/include/linux/ip_vs.h 2010-07-27 06:20:24.000000000 +0900
@@ -326,6 +326,9 @@ enum {
IPVS_SVC_ATTR_NETMASK, /* persistent netmask */
IPVS_SVC_ATTR_STATS, /* nested attribute for service stats */
+
+ IPVS_SVC_ATTR_PE_NAME, /* name of ct retriever */
+
__IPVS_SVC_ATTR_MAX,
};
Index: nf-next-2.6/include/net/ip_vs.h
===================================================================
--- nf-next-2.6.orig/include/net/ip_vs.h 2010-07-27 06:20:20.000000000 +0900
+++ nf-next-2.6/include/net/ip_vs.h 2010-07-27 06:20:24.000000000 +0900
@@ -442,6 +442,7 @@ struct ip_vs_service_user_kern {
/* virtual service options */
char *sched_name;
+ char *pe_name;
unsigned flags; /* virtual service flags */
unsigned timeout; /* persistent timeout in sec */
u32 netmask; /* persistent netmask */
^ permalink raw reply
* [patch v1 11/12] IPVS: Fallback if persistence engine fails
From: Simon Horman @ 2010-08-22 12:45 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
[-- Attachment #1: pe-fallback.patch --]
[-- Type: text/plain, Size: 2929 bytes --]
Fall back to normal persistence handling if the persistence
engine fails to recognise a packet.
This way, at least the packet will go somewhere.
It is envisaged that iptables could be used to block packets
such if this is not desired although nf_conntrack_sip would
likely need to be enhanced first.
Signed-off-by: Simon Horman <horms@verge.net.au>
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_conn.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_conn.c 2010-07-27 22:10:18.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_conn.c 2010-07-27 22:12:05.000000000 +0900
@@ -150,7 +150,7 @@ static unsigned int ip_vs_conn_hashkey(i
static unsigned int ip_vs_conn_hashkey_param(const struct ip_vs_conn_param *p)
{
- if (p->pe && p->pe->hashkey_raw)
+ if (p->pe_data && p->pe->hashkey_raw)
return p->pe->hashkey_raw(p, ip_vs_conn_rnd) &
ip_vs_conn_tab_mask;
return ip_vs_conn_hashkey(p->af, p->protocol, p->caddr, p->cport);
@@ -340,7 +340,7 @@ struct ip_vs_conn *ip_vs_ct_in_get(const
ct_read_lock(hash);
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
- if (p->pe && p->pe->ct_match) {
+ if (p->pe_data && p->pe->ct_match) {
if (p->pe->ct_match(p, cp))
goto out;
continue;
@@ -927,7 +927,7 @@ static int ip_vs_conn_seq_show(struct se
char pe_data[IP_VS_PENAME_MAXLEN + IP_VS_PEDATA_MAXLEN + 3];
size_t len = 0;
- if (cp->dest->svc->pe && cp->dest->svc->pe->show_pe_data) {
+ if (cp->pe_data && cp->dest->svc->pe->show_pe_data) {
pe_data[0] = ' ';
len = strlen(cp->dest->svc->pe->name);
memcpy(pe_data + 1, cp->dest->svc->pe->name, len);
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_core.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_core.c 2010-07-27 22:10:18.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_core.c 2010-07-27 22:12:05.000000000 +0900
@@ -175,7 +175,7 @@ ip_vs_set_state(struct ip_vs_conn *cp, i
return pp->state_transition(cp, direction, skb, pp);
}
-static inline int
+static inline void
ip_vs_conn_fill_param_persist(const struct ip_vs_service *svc,
struct sk_buff *skb, int protocol,
const union nf_inet_addr *caddr, __be16 cport,
@@ -185,8 +185,7 @@ ip_vs_conn_fill_param_persist(const stru
ip_vs_conn_fill_param(svc->af, protocol, caddr, cport, vaddr, vport, p);
p->pe = svc->pe;
if (p->pe && p->pe->fill_param)
- return p->pe->fill_param(p, skb);
- return 0;
+ p->pe->fill_param(p, skb);
}
/*
@@ -267,9 +266,8 @@ ip_vs_sched_persist(struct ip_vs_service
vaddr = &fwmark;
}
}
- if (ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0,
- vaddr, vport, ¶m))
- return NULL;
+ ip_vs_conn_fill_param_persist(svc, skb, protocol, &snet, 0,
+ vaddr, vport, ¶m);
}
/* Check if a template already exists */
^ permalink raw reply
* [patch v1 12/12] IPVS: sip persistence engine
From: Simon Horman @ 2010-08-22 12:45 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
[-- Attachment #1: ip_vs_pe_sip.patch --]
[-- Type: text/plain, Size: 6620 bytes --]
Add the SIP callid as a key for persistence.
This allows multiple connections from the same IP address to be
differentiated on the basis of the callid.
When used in conjunction with the persistence mask, it allows connections
from different IP addresses to be aggregated on the basis of the callid.
It is envisaged that a persistence mask of 0.0.0.0 will be a useful
setting. That is, ignore the source IP address when checking for
persistence.
It is envisaged that this option will be used in conjunction with
one-packet scheduling.
This only works with UDP and cannot be made to work with TCP
within the current framework.
Signed-off-by: Simon Horman <horms@verge.net.au>
v1
* Use buf[] instead of poiter arithmetic in ip_vs_dbg_callid()
As suggested by Jan Engelhardt
Index: nf-next-2.6/net/netfilter/ipvs/Kconfig
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/Kconfig 2010-08-04 16:58:26.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/Kconfig 2010-08-20 22:34:19.000000000 +0900
@@ -247,4 +247,11 @@ config IP_VS_FTP
If you want to compile it in kernel, say Y. To compile it as a
module, choose M here. If unsure, say N.
+config IP_VS_PE_SIP
+ tristate "SIP persistence engine"
+ depends on IP_VS_PROTO_UDP
+ depends on NF_CONNTRACK_SIP
+ ---help---
+ Allow persistence based on the SIP Call-ID
+
endif # IP_VS
Index: nf-next-2.6/net/netfilter/ipvs/Makefile
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/Makefile 2010-08-20 21:57:56.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/Makefile 2010-08-20 22:34:19.000000000 +0900
@@ -32,3 +32,6 @@ obj-$(CONFIG_IP_VS_NQ) += ip_vs_nq.o
# IPVS application helpers
obj-$(CONFIG_IP_VS_FTP) += ip_vs_ftp.o
+
+# IPVS connection template retrievers
+obj-$(CONFIG_IP_VS_PE_SIP) += ip_vs_pe_sip.o
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_pe_sip.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_pe_sip.c 2010-08-20 22:35:12.000000000 +0900
@@ -0,0 +1,167 @@
+#define KMSG_COMPONENT "IPVS"
+#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <net/ip_vs.h>
+#include <net/netfilter/nf_conntrack.h>
+#include <linux/netfilter/nf_conntrack_sip.h>
+
+static const char *ip_vs_dbg_callid(char *buf, size_t buf_len,
+ const char *callid, size_t callid_len,
+ int *idx)
+{
+ size_t len = min(min(callid_len, (size_t)64), buf_len - *idx - 1);
+ memcpy(buf + *idx, callid, len);
+ buf[*idx+len] = '\0';
+ *idx += len + 1;
+ return buf + *idx - len;
+}
+
+#define IP_VS_DEBUG_CALLID(callid, len) \
+ ip_vs_dbg_callid(ip_vs_dbg_buf, sizeof(ip_vs_dbg_buf), \
+ callid, len, &ip_vs_dbg_idx)
+
+static int get_callid(const char *dptr, unsigned int dataoff,
+ unsigned int datalen,
+ unsigned int *matchoff, unsigned int *matchlen)
+{
+ /* Find callid */
+ while (1) {
+ int ret = ct_sip_get_header(NULL, dptr, dataoff, datalen,
+ SIP_HDR_CALL_ID, matchoff,
+ matchlen);
+ if (ret > 0)
+ break;
+ if (!ret)
+ return 0;
+ dataoff += *matchoff;
+ }
+
+ /* Empty callid is useless */
+ if (!*matchlen)
+ return -EINVAL;
+
+ /* Too large is useless */
+ if (*matchlen > IP_VS_PEDATA_MAXLEN)
+ return -EINVAL;
+
+ /* SIP headers are always followed by a line terminator */
+ if (*matchoff + *matchlen == datalen)
+ return -EINVAL;
+
+ /* RFC 2543 allows lines to be terminated with CR, LF or CRLF,
+ * RFC 3261 allows only CRLF, we support both. */
+ if (*(dptr + *matchoff + *matchlen) != '\r' &&
+ *(dptr + *matchoff + *matchlen) != '\n')
+ return -EINVAL;
+
+ IP_VS_DBG_BUF(9, "SIP callid %s (%d bytes)\n",
+ IP_VS_DEBUG_CALLID(dptr + *matchoff, *matchlen),
+ *matchlen);
+ return 0;
+}
+
+static int
+ip_vs_sip_fill_param(struct ip_vs_conn_param *p, struct sk_buff *skb)
+{
+ struct ip_vs_iphdr iph;
+ unsigned int dataoff, datalen, matchoff, matchlen;
+ const char *dptr;
+
+ ip_vs_fill_iphdr(p->af, skb_network_header(skb), &iph);
+
+ /* Only useful with UDP */
+ if (iph.protocol != IPPROTO_UDP)
+ return -EINVAL;
+
+ /* No Data ? */
+ dataoff = iph.len + sizeof(struct udphdr);
+ if (dataoff >= skb->len)
+ return -EINVAL;
+
+ dptr = skb->data + dataoff;
+ datalen = skb->len - dataoff;
+
+ if (get_callid(dptr, dataoff, datalen, &matchoff, &matchlen))
+ return -EINVAL;
+
+ p->pe_data = kmalloc(matchlen, GFP_KERNEL);
+ if (!p->pe_data)
+ return -ENOMEM;
+
+ /* N.B: pe_data is only set on success,
+ * this alows fallback to the default persistance logic on failure
+ */
+ memcpy(p->pe_data, dptr + matchoff, matchlen);
+ p->pe_data_len = matchlen;
+
+ return 0;
+}
+
+static bool ip_vs_sip_ct_match(const struct ip_vs_conn_param *p,
+ struct ip_vs_conn *ct)
+
+{
+ bool ret = 0;
+
+ if (ct->af == p->af &&
+ ip_vs_addr_equal(p->af, p->caddr, &ct->caddr) &&
+ /* protocol should only be IPPROTO_IP if
+ * d_addr is a fwmark */
+ ip_vs_addr_equal(p->protocol == IPPROTO_IP ? AF_UNSPEC : p->af,
+ p->vaddr, &ct->vaddr) &&
+ ct->vport == p->vport &&
+ ct->flags & IP_VS_CONN_F_TEMPLATE &&
+ ct->protocol == p->protocol &&
+ ct->pe_data && ct->pe_data_len == p->pe_data_len &&
+ !strnicmp(ct->pe_data, p->pe_data, p->pe_data_len))
+ ret = 1;
+
+ IP_VS_DBG_BUF(9, "SIP template match %s %s->%s:%d %s\n",
+ ip_vs_proto_name(p->protocol),
+ IP_VS_DEBUG_CALLID(p->pe_data, p->pe_data_len),
+ IP_VS_DBG_ADDR(p->af, p->vaddr), ntohs(p->vport),
+ ret ? "hit" : "not hit");
+
+ return ret;
+}
+
+static u32 ip_vs_sip_hashkey_raw(const struct ip_vs_conn_param *p,
+ u32 initval)
+{
+ return jhash(p->pe_data, p->pe_data_len, initval);
+}
+
+static int ip_vs_sip_show_pe_data(const struct ip_vs_conn *cp, char *buf)
+{
+ memcpy(buf, cp->pe_data, cp->pe_data_len);
+ return cp->pe_data_len;
+}
+
+static struct ip_vs_pe ip_vs_sip_pe =
+{
+ .name = "sip",
+ .refcnt = ATOMIC_INIT(0),
+ .module = THIS_MODULE,
+ .n_list = LIST_HEAD_INIT(ip_vs_sip_pe.n_list),
+ .fill_param = ip_vs_sip_fill_param,
+ .ct_match = ip_vs_sip_ct_match,
+ .hashkey_raw = ip_vs_sip_hashkey_raw,
+ .show_pe_data = ip_vs_sip_show_pe_data,
+};
+
+static int __init ip_vs_sip_init(void)
+{
+ return register_ip_vs_pe(&ip_vs_sip_pe);
+}
+
+static void __exit ip_vs_sip_cleanup(void)
+{
+ unregister_ip_vs_pe(&ip_vs_sip_pe);
+}
+
+module_init(ip_vs_sip_init);
+module_exit(ip_vs_sip_cleanup);
+MODULE_LICENSE("GPL");
^ permalink raw reply
* [patch v1 0/2] ipvsadm: SIP Persistence Engine
From: Simon Horman @ 2010-08-22 12:49 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
This series is the ipvsadm companion to the kernel
patch series "IPVS: SIP Persistence Engine".
^ permalink raw reply
* [patch v1 1/2] [PATCH 1/2] Slightly simplify options conflicts logic
From: Simon Horman @ 2010-08-22 12:49 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124946.374697950@vergenet.net>
[-- Attachment #1: 0001-Slightly-simplify-options-conflicts-logic.patch --]
[-- Type: text/plain, Size: 744 bytes --]
Signed-off-by: Simon Horman <horms@verge.net.au>
diff --git a/ipvsadm.c b/ipvsadm.c
index 76ec7c4..1ac6c7f 100644
--- a/ipvsadm.c
+++ b/ipvsadm.c
@@ -763,11 +763,9 @@ static int process_options(int argc, char **argv, int reading_stdin)
switch (ce.cmd) {
case CMD_LIST:
- if ((options & OPT_CONNECTION ||
- options & OPT_TIMEOUT || options & OPT_DAEMON) &&
- (options & OPT_STATS ||
- options & OPT_PERSISTENTCONN ||
- options & OPT_RATE || options & OPT_THRESHOLDS))
+ if (options & (OPT_CONNECTION|OPT_TIMEOUT|OPT_DAEMON) &&
+ options & (OPT_STATS|OPT_PERSISTENTCONN|
+ OPT_RATE|OPT_THRESHOLDS))
fail(2, "options conflicts in the list command");
if (options & OPT_CONNECTION)
--
1.7.1
^ permalink raw reply related
* [patch v1 2/2] [PATCH 2/2] Add support for persistence engines.
From: Simon Horman @ 2010-08-22 12:49 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124946.374697950@vergenet.net>
[-- Attachment #1: 0002-Add-support-for-persistence-engines.patch --]
[-- Type: text/plain, Size: 13494 bytes --]
This adds the --pe [engine] option to the -A and -E commands
which allows a persistence engine to be associated with a virtual service.
The absence of --pe sets no persistence engine.
The --pe option only works when ipvsadm is compiled to use netlink
for user-space/kernel communication.
This patch also allows the --persistent-conn option to be given to the -L
command, which will list persistence engine data, if any is present, when
listing connections (and persistence templates).
At this time the only (proposed) persistence engine is sip.
Signed-off-by: Simon Horman <horms@verge.net.au>
---
v0.4
* Fix indentation of --pe help text
diff --git a/Makefile b/Makefile
index 46300ef..23274e5 100644
--- a/Makefile
+++ b/Makefile
@@ -29,6 +29,7 @@ NAME = ipvsadm
VERSION = $(shell cat VERSION)
RELEASE = 1
SCHEDULERS = "$(shell cat SCHEDULERS)"
+PE_LIST = "$(shell cat PERSISTENCE_ENGINES)"
PROGROOT = $(shell basename `pwd`)
ARCH = $(shell uname -m)
RPMSOURCEDIR = $(shell rpm --eval '%_sourcedir')
@@ -83,7 +84,7 @@ ifneq (0,$(HAVE_NL))
LIBS += -lnl
endif
DEFINES = -DVERSION=\"$(VERSION)\" -DSCHEDULERS=\"$(SCHEDULERS)\" \
- $(POPT_DEFINE)
+ -DPE_LIST=\"$(PE_LIST)\" $(POPT_DEFINE)
DEFINES += $(shell if [ ! -f ../ip_vs.h ]; then \
echo "-DHAVE_NET_IP_VS_H"; fi;)
diff --git a/PERSISTENCE_ENGINES b/PERSISTENCE_ENGINES
new file mode 100644
index 0000000..641cf83
--- /dev/null
+++ b/PERSISTENCE_ENGINES
@@ -0,0 +1 @@
+sip
diff --git a/ipvsadm.8 b/ipvsadm.8
index 816e307..001ae74 100644
--- a/ipvsadm.8
+++ b/ipvsadm.8
@@ -391,6 +391,10 @@ with this option will display the persistent connection counter
information of each server in service listing. The persistent
connection is used to forward the actual connections from the same
client/network to the same server.
+.sp
+The \fIlist\fP command with the -c, --connection option and this option
+will include persistence engine data, if any is present, when listing
+connections.
.TP
.B --sort
Sort the list of virtual services and real servers. The virtual
diff --git a/ipvsadm.c b/ipvsadm.c
index 1ac6c7f..0332b22 100644
--- a/ipvsadm.c
+++ b/ipvsadm.c
@@ -181,13 +181,15 @@ static const char* cmdnames[] = {
#define OPT_SYNCID 0x080000
#define OPT_EXACT 0x100000
#define OPT_ONEPACKET 0x200000
-#define NUMBER_OF_OPT 22
+#define OPT_PERSISTENCE_ENGINE 0x400000
+#define NUMBER_OF_OPT 23
static const char* optnames[] = {
"numeric",
"connection",
"service-address",
"scheduler",
+ "pe",
"persistent",
"netmask",
"real-server",
@@ -282,6 +284,7 @@ enum {
TAG_PERSISTENTCONN,
TAG_SORT,
TAG_NO_SORT,
+ TAG_PERSISTENCE_ENGINE,
};
/* various parsing helpers & parsing functions */
@@ -421,6 +424,8 @@ parse_options(int argc, char **argv, struct ipvs_command_entry *ce,
{ "exact", 'X', POPT_ARG_NONE, NULL, 'X', NULL, NULL },
{ "ipv6", '6', POPT_ARG_NONE, NULL, '6', NULL, NULL },
{ "ops", 'o', POPT_ARG_NONE, NULL, 'o', NULL, NULL },
+ { "pe", '\0', POPT_ARG_STRING, &optarg, TAG_PERSISTENCE_ENGINE,
+ NULL, NULL },
{ NULL, 0, 0, NULL, 0, NULL, NULL }
};
@@ -647,6 +652,10 @@ parse_options(int argc, char **argv, struct ipvs_command_entry *ce,
set_option(options, OPT_ONEPACKET);
ce->svc.flags |= IP_VS_SVC_F_ONEPACKET;
break;
+ case TAG_PERSISTENCE_ENGINE:
+ set_option(options, OPT_PERSISTENCE_ENGINE);
+ strncpy(ce->svc.pe_name, optarg, IP_VS_PENAME_MAXLEN);
+ break;
default:
fail(2, "invalid option `%s'",
poptBadOption(context, POPT_BADOPTION_NOALIAS));
@@ -763,9 +772,10 @@ static int process_options(int argc, char **argv, int reading_stdin)
switch (ce.cmd) {
case CMD_LIST:
- if (options & (OPT_CONNECTION|OPT_TIMEOUT|OPT_DAEMON) &&
- options & (OPT_STATS|OPT_PERSISTENTCONN|
- OPT_RATE|OPT_THRESHOLDS))
+ if ((options & (OPT_CONNECTION|OPT_TIMEOUT|OPT_DAEMON) &&
+ options & (OPT_STATS|OPT_RATE|OPT_THRESHOLDS)) ||
+ (options & (OPT_TIMEOUT|OPT_DAEMON) &&
+ options & OPT_PERSISTENTCONN))
fail(2, "options conflicts in the list command");
if (options & OPT_CONNECTION)
@@ -1060,7 +1070,7 @@ static void usage_exit(const char *program, const int exit_status)
version(stream);
fprintf(stream,
"Usage:\n"
- " %s -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] [-M netmask]\n"
+ " %s -A|E -t|u|f service-address [-s scheduler] [-p [timeout]] [-M netmask] [--pe persistence_engine]\n"
" %s -D -t|u|f service-address\n"
" %s -C\n"
" %s -R\n"
@@ -1105,6 +1115,8 @@ static void usage_exit(const char *program, const int exit_status)
" --ipv6 -6 fwmark entry uses IPv6\n"
" --scheduler -s scheduler one of " SCHEDULERS ",\n"
" the default scheduler is %s.\n"
+ " --pe engine alternate persistence engine may be " PE_LIST ",\n"
+ " not set by default.\n"
" --persistent -p [timeout] persistent service\n"
" --netmask -M netmask persistent granularity mask\n"
" --real-server -r server-address server-address is host (and port)\n"
@@ -1225,6 +1237,8 @@ static void print_conn(char *buf, unsigned int format)
char state[16];
unsigned int expires;
unsigned short af = AF_INET;
+ char pe_name[IP_VS_PENAME_MAXLEN];
+ char pe_data[IP_VS_PEDATA_MAXLEN];
int n;
char temp1[INET6_ADDRSTRLEN], temp2[INET6_ADDRSTRLEN], temp3[INET6_ADDRSTRLEN];
@@ -1232,9 +1246,10 @@ static void print_conn(char *buf, unsigned int format)
unsigned int minutes, seconds;
char expire_str[12];
- if ((n = sscanf(buf, "%s %s %hX %s %hX %s %hX %s %d",
+ if ((n = sscanf(buf, "%s %s %hX %s %hX %s %hX %s %d %s %s",
protocol, temp1, &cport, temp2, &vport,
- temp3, &dport, state, &expires)) == -1)
+ temp3, &dport, state, &expires,
+ pe_name, pe_data)) == -1)
exit(1);
if (strcmp(protocol, "TCP") == 0)
@@ -1268,8 +1283,13 @@ static void print_conn(char *buf, unsigned int format)
minutes = expires / 60;
sprintf(expire_str, "%02d:%02d", minutes, seconds);
- printf("%-3s %-6s %-11s %-18s %-18s %s\n",
- protocol, expire_str, state, cname, vname, dname);
+ if (format & FMT_PERSISTENTCONN)
+ printf("%-3s %-6s %-11s %-18s %-18s %-16s %-18s %s\n",
+ protocol, expire_str, state, cname, vname, dname,
+ pe_name, pe_data);
+ else
+ printf("%-3s %-6s %-11s %-18s %-18s %s\n",
+ protocol, expire_str, state, cname, vname, dname);
free(cname);
free(vname);
@@ -1295,8 +1315,13 @@ void list_conn(unsigned int format)
exit(1);
}
printf("IPVS connection entries\n");
- printf("pro expire %-11s %-18s %-18s %s\n",
- "state", "source", "virtual", "destination");
+ if (format & FMT_PERSISTENTCONN)
+ printf("pro expire %-11s %-18s %-18s %-18s %-16s %s\n",
+ "state", "source", "virtual", "destination",
+ "pe name", "pe_data");
+ else
+ printf("pro expire %-11s %-18s %-18s %s\n",
+ "state", "source", "virtual", "destination");
/*
* Print the VS information according to the format
@@ -1459,6 +1484,8 @@ print_service_entry(ipvs_service_entry_t *se, unsigned int format)
printf(" -M %i", se->netmask);
}
}
+ if (se->pe_name[0])
+ printf(" pe %s", se->pe_name);
if (se->flags & IP_VS_SVC_F_ONEPACKET)
printf(" ops");
} else if (format & FMT_STATS) {
@@ -1488,6 +1515,8 @@ print_service_entry(ipvs_service_entry_t *se, unsigned int format)
if (se->af == AF_INET6)
if (se->netmask != 128)
printf(" mask %i", se->netmask);
+ if (se->pe_name[0])
+ printf(" pe %s", se->pe_name);
if (se->flags & IP_VS_SVC_F_ONEPACKET)
printf(" ops");
}
diff --git a/libipvs/ip_vs.h b/libipvs/ip_vs.h
index 843c51a..9726a17 100644
--- a/libipvs/ip_vs.h
+++ b/libipvs/ip_vs.h
@@ -92,8 +92,11 @@
#define IP_VS_CONN_F_ONE_PACKET 0x2000 /* forward only one packet */
#define IP_VS_SCHEDNAME_MAXLEN 16
+#define IP_VS_PENAME_MAXLEN 16
#define IP_VS_IFNAME_MAXLEN 16
+#define IP_VS_PEDATA_MAXLEN 255
+
union nf_inet_addr {
__u32 all[4];
__be32 ip;
@@ -134,6 +137,7 @@ struct ip_vs_service_user {
__be32 netmask; /* persistent netmask */
u_int16_t af;
union nf_inet_addr addr;
+ char pe_name[IP_VS_PENAME_MAXLEN];
};
struct ip_vs_dest_kern {
@@ -240,6 +244,7 @@ struct ip_vs_service_entry {
u_int16_t af;
union nf_inet_addr addr;
+ char pe_name[IP_VS_PENAME_MAXLEN];
};
@@ -429,6 +434,9 @@ enum {
IPVS_SVC_ATTR_NETMASK, /* persistent netmask */
IPVS_SVC_ATTR_STATS, /* nested attribute for service stats */
+
+ IPVS_SVC_ATTR_PE_NAME, /* name of scheduler */
+
__IPVS_SVC_ATTR_MAX,
};
diff --git a/libipvs/libipvs.c b/libipvs/libipvs.c
index 979d5bd..a157e18 100644
--- a/libipvs/libipvs.c
+++ b/libipvs/libipvs.c
@@ -40,6 +40,15 @@ static int family, try_nl = 1;
{ errno = EAFNOSUPPORT; return ret; } \
s->__addr_v4 = s->addr.ip; \
+#define CHECK_PE(s, ret) if (s->pe_name) \
+ { errno = EAFNOSUPPORT; return ret; }
+
+#define CHECK_COMPAT_DEST(s, ret) CHECK_IPV4(s, ret)
+
+#define CHECK_COMPAT_SVC(s, ret) \
+ CHECK_IPV4(s, ret); \
+ CHECK_PE(s, ret);
+
#ifdef LIBIPVS_USE_NL
struct nl_msg *ipvs_nl_message(int cmd, int flags)
{
@@ -218,6 +227,8 @@ static int ipvs_nl_fill_service_attr(struct nl_msg *msg, ipvs_service_t *svc)
}
NLA_PUT_STRING(msg, IPVS_SVC_ATTR_SCHED_NAME, svc->sched_name);
+ if (svc->pe_name)
+ NLA_PUT_STRING(msg, IPVS_SVC_ATTR_PE_NAME, svc->pe_name);
NLA_PUT(msg, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags);
NLA_PUT_U32(msg, IPVS_SVC_ATTR_TIMEOUT, svc->timeout);
NLA_PUT_U32(msg, IPVS_SVC_ATTR_NETMASK, svc->netmask);
@@ -245,7 +256,7 @@ int ipvs_add_service(ipvs_service_t *svc)
}
#endif
- CHECK_IPV4(svc, -1);
+ CHECK_COMPAT_SVC(svc, -1);
return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ADD, (char *)svc,
sizeof(struct ip_vs_service_kern));
}
@@ -265,7 +276,7 @@ int ipvs_update_service(ipvs_service_t *svc)
return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL);
}
#endif
- CHECK_IPV4(svc, -1);
+ CHECK_COMPAT_SVC(svc, -1);
return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_EDIT, (char *)svc,
sizeof(struct ip_vs_service_kern));
}
@@ -285,7 +296,7 @@ int ipvs_del_service(ipvs_service_t *svc)
return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL);
}
#endif
- CHECK_IPV4(svc, -1);
+ CHECK_COMPAT_SVC(svc, -1);
return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_DEL, (char *)svc,
sizeof(struct ip_vs_service_kern));
}
@@ -310,7 +321,7 @@ int ipvs_zero_service(ipvs_service_t *svc)
return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL);
}
#endif
- CHECK_IPV4(svc, -1);
+ CHECK_COMPAT_SVC(svc, -1);
return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ZERO, (char *)svc,
sizeof(struct ip_vs_service_kern));
}
@@ -360,8 +371,8 @@ nla_put_failure:
}
#endif
- CHECK_IPV4(svc, -1);
- CHECK_IPV4(dest, -1);
+ CHECK_COMPAT_SVC(svc, -1);
+ CHECK_COMPAT_DEST(dest, -1);
memcpy(&svcdest.svc, svc, sizeof(svcdest.svc));
memcpy(&svcdest.dest, dest, sizeof(svcdest.dest));
return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ADDDEST,
@@ -389,8 +400,8 @@ nla_put_failure:
return -1;
}
#endif
- CHECK_IPV4(svc, -1);
- CHECK_IPV4(dest, -1);
+ CHECK_COMPAT_SVC(svc, -1);
+ CHECK_COMPAT_DEST(dest, -1);
memcpy(&svcdest.svc, svc, sizeof(svcdest.svc));
memcpy(&svcdest.dest, dest, sizeof(svcdest.dest));
return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_EDITDEST,
@@ -419,8 +430,8 @@ nla_put_failure:
}
#endif
- CHECK_IPV4(svc, -1);
- CHECK_IPV4(dest, -1);
+ CHECK_COMPAT_SVC(svc, -1);
+ CHECK_COMPAT_DEST(dest, -1);
memcpy(&svcdest.svc, svc, sizeof(svcdest.svc));
memcpy(&svcdest.dest, dest, sizeof(svcdest.dest));
return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_DELDEST,
@@ -593,6 +604,11 @@ static int ipvs_services_parse_cb(struct nl_msg *msg, void *arg)
nla_get_string(svc_attrs[IPVS_SVC_ATTR_SCHED_NAME]),
IP_VS_SCHEDNAME_MAXLEN);
+ if (svc_attrs[IPVS_SVC_ATTR_PE_NAME])
+ strncpy(get->entrytable[i].pe_name,
+ nla_get_string(svc_attrs[IPVS_SVC_ATTR_PE_NAME]),
+ IP_VS_PENAME_MAXLEN);
+
get->entrytable[i].netmask = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_NETMASK]);
get->entrytable[i].timeout = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_TIMEOUT]);
nla_memcpy(&flags, svc_attrs[IPVS_SVC_ATTR_FLAGS], sizeof(flags));
@@ -937,7 +953,8 @@ ipvs_get_service_err2:
}
#endif
- CHECK_IPV4(svc, NULL);
+ CHECK_COMPAT_SVC(svc, NULL);
+ CHECK_PE(svc, NULL);
if (getsockopt(sockfd, IPPROTO_IP, IP_VS_SO_GET_SERVICE,
(char *)svc, &len)) {
free(svc);
@@ -945,6 +962,7 @@ ipvs_get_service_err2:
}
svc->af = AF_INET;
svc->addr.ip = svc->__addr_v4;
+ svc->pe_name[0] = '\0';
return svc;
}
@@ -1086,9 +1104,9 @@ const char *ipvs_strerror(int err)
const char *message;
} table [] = {
{ ipvs_add_service, EEXIST, "Service already exists" },
- { ipvs_add_service, ENOENT, "Scheduler not found" },
+ { ipvs_add_service, ENOENT, "Scheduler or persistence engine not found" },
{ ipvs_update_service, ESRCH, "No such service" },
- { ipvs_update_service, ENOENT, "Scheduler not found" },
+ { ipvs_update_service, ENOENT, "Scheduler or persistence engine not found" },
{ ipvs_del_service, ESRCH, "No such service" },
{ ipvs_zero_service, ESRCH, "No such service" },
{ ipvs_add_dest, ESRCH, "Service not defined" },
--
1.7.1
^ permalink raw reply related
* Re: [patch v1 00/12] IPVS: SIP Persistence Engine
From: Simon Horman @ 2010-08-22 12:57 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
On Sun, Aug 22, 2010 at 09:44:57PM +0900, Simon Horman wrote:
> This patch series adds load-balancing of UDP SIP based on Call-ID to
> IPVS as well as a frame-work for extending IPVS to handle alternate
> persistence requirements.
>
> REVISIONS
>
> This is "patch v1" of this series, which addresses a few minor problems, as
> annotated on a per-patch basis, since the initial "rfc" posting. Internally
> there were 4 rfc versions, 0.1, 0.2, 0.3 and 0.4, some of the notes for
> some of the patches reflect those versions.
>
> OVERVIEW
>
> The approach that I have taken is what I call persistence engines.
> The basic idea being that you can provide a module to LVS that alters
> the way that it handles connection templates, which are at the core
> of persistence. In particular, an additional key can be added, and
> any of the normal IP address, port and protocol information can either
> be used or ignored.
>
> In the case of the SIP persistence engine, the only persistence engine, all
> the keys used by the default persistence behaviour are used and the callid
> is added as an extra key. I originally intended to ignore the cip, but this
> can optionally be done by setting the persistence mask (-M) to 0.0.0.0
> while allowing the flexibility of other mask values.
>
> It is envisaged that the SIP persistence engine will be used in conjunction
> with one-packet scheduling. I'm interested to hear if that doesn't fit your
> needs.
>
>
> CONFIGURATION
>
> A persistence engine is associated with a virtual service
> (as are schedulers). I have added the --pe option to the
> ivpsadm -A and -E commands to allow the persistence engine
> of a virtual service to be added, changed, or deleted.
>
> e.g. ipvsadm -A -u 10.4.3.192:5060 -p 60 -M 0.0.0.0 -o --pe sip
>
> There are no other configuration parameters at this time.
>
>
> RUNNING
>
> When a connection template is created, if its virtual service
> has a persistence engine, then the persistence engine can add
> an extra key to the connection template. For the SIP module this
> is the callid. More generically, it is known as "pe data". And
> both the name of the persistence engine, "pe name", and "pe data"
> can be viewed in /proc/net/ip_vs_conn and by passing the
> --persistent-conn option to ipvsadm -Lc.
>
> e.g.
> # ipvsadm -Lcn --persistent-conn
> UDP 00:38 UDP 10.4.3.0:0 10.4.3.192:5060 127.0.0.1:5060 sip 193373839
>
> Here we see a single persistence template (cport is 0), which has been
> handled by the sip persistence engine. The pe data (callid) is 193373839.
>
> In the case where the persistence engine can't match a packet for some
> reason, the connection will fall back to the normal persistence handling.
> This seems reasonable, as that if the packet ought to be dropped, iptables
> could be used.
>
> A limited amount of debugging information has been added which
> can be enabled using a value of 9 or greater in
> /proc/sys/net/ipv4/vs/debug_level
>
> CODE AVAILABILITY
>
> The kernel patches (13) are available in git as the pe-0.4 branch of
> git://git.kernel.org/pub/scm/linux/kernel/git/horms/lvs-test-2.6.git
>
> The ipvsadm patches (2) are available in git as the pe-0.4 branch of
> git://github.com/horms/ipvsadm-test.git
pe-0.4 should read pe-1 above (x2).
pe-0.4 is an older revision.
> I will post the ipvsadm patches separately
^ permalink raw reply
* [patch v1 06/12] IPVS: ip_vs_{un,}bind_scheduler NULL arguments
From: Simon Horman @ 2010-08-22 12:45 UTC (permalink / raw)
To: lvs-devel, netdev, netfilter, netfilter-devel
Cc: Jan Engelhardt, Stephen Hemminger, Wensong Zhang,
Julian Anastasov, Patrick McHardy
In-Reply-To: <20100822124457.339517323@vergenet.net>
[-- Attachment #1: ip_vs_bind_scheduler-null.patch --]
[-- Type: text/plain, Size: 1918 bytes --]
In general NULL arguments aren't passed by the few callers that exist,
so don't test for them.
The exception is to make passing NULL to ip_vs_unbind_scheduler() a noop.
Signed-off-by: Simon Horman <horms@verge.net.au>
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_ctl.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_ctl.c 2010-07-22 22:04:29.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_ctl.c 2010-07-22 22:07:18.000000000 +0900
@@ -1229,8 +1229,7 @@ ip_vs_add_service(struct ip_vs_service_u
out_err:
if (svc != NULL) {
- if (svc->scheduler)
- ip_vs_unbind_scheduler(svc);
+ ip_vs_unbind_scheduler(svc);
if (svc->inc) {
local_bh_disable();
ip_vs_app_inc_put(svc->inc);
Index: nf-next-2.6/net/netfilter/ipvs/ip_vs_sched.c
===================================================================
--- nf-next-2.6.orig/net/netfilter/ipvs/ip_vs_sched.c 2010-07-22 22:04:23.000000000 +0900
+++ nf-next-2.6/net/netfilter/ipvs/ip_vs_sched.c 2010-07-22 22:06:20.000000000 +0900
@@ -46,15 +46,6 @@ int ip_vs_bind_scheduler(struct ip_vs_se
{
int ret;
- if (svc == NULL) {
- pr_err("%s(): svc arg NULL\n", __func__);
- return -EINVAL;
- }
- if (scheduler == NULL) {
- pr_err("%s(): scheduler arg NULL\n", __func__);
- return -EINVAL;
- }
-
svc->scheduler = scheduler;
if (scheduler->init_service) {
@@ -74,18 +65,10 @@ int ip_vs_bind_scheduler(struct ip_vs_se
*/
int ip_vs_unbind_scheduler(struct ip_vs_service *svc)
{
- struct ip_vs_scheduler *sched;
+ struct ip_vs_scheduler *sched = svc->scheduler;
- if (svc == NULL) {
- pr_err("%s(): svc arg NULL\n", __func__);
- return -EINVAL;
- }
-
- sched = svc->scheduler;
- if (sched == NULL) {
- pr_err("%s(): svc isn't bound\n", __func__);
- return -EINVAL;
- }
+ if (!sched)
+ return 0;
if (sched->done_service) {
if (sched->done_service(svc) != 0) {
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox