Discussion:
[Linuxptp-devel] [PATCH] Add detection for duplicated pdelay response with the same pid and sequence id
Delio Brignoli
2013-03-13 14:22:01 UTC
Permalink
Signed-off-by: Delio Brignoli <***@audioscience.com>
---
port.c | 9 ++++++++-
1 files changed, 8 insertions(+), 1 deletions(-)

diff --git a/port.c b/port.c
index 3b3930f..dc4ba3a 100644
--- a/port.c
+++ b/port.c
@@ -1458,7 +1458,14 @@ calc:
static int process_pdelay_resp(struct port *p, struct ptp_message *m)
{
if (p->peer_delay_resp) {
- if (!source_pid_eq(p->peer_delay_resp, m)) {
+ int same_pid = source_pid_eq(p->peer_delay_resp, m);
+ int same_sid = (p->peer_delay_resp->header.sequenceId ==
+ m->header.sequenceId);
+ if (same_sid && same_pid) {
+ pr_err("port %hu: multiple identical peer responses", portnum(p));
+ return -1;
+ }
+ if (same_sid && !same_pid) {
pr_err("port %hu: multiple peer responses", portnum(p));
return -1;
}
--
1.7.0.4
Delio Brignoli
2013-03-15 12:25:56 UTC
Permalink
Hello Richard,

Any comments about this patch?

Thanks
--
Delio
Post by Delio Brignoli
---
port.c | 9 ++++++++-
1 files changed, 8 insertions(+), 1 deletions(-)
diff --git a/port.c b/port.c
index 3b3930f..dc4ba3a 100644
--- a/port.c
+++ b/port.c
static int process_pdelay_resp(struct port *p, struct ptp_message *m)
{
if (p->peer_delay_resp) {
- if (!source_pid_eq(p->peer_delay_resp, m)) {
+ int same_pid = source_pid_eq(p->peer_delay_resp, m);
+ int same_sid = (p->peer_delay_resp->header.sequenceId ==
+ m->header.sequenceId);
+ if (same_sid && same_pid) {
+ pr_err("port %hu: multiple identical peer responses", portnum(p));
+ return -1;
+ }
+ if (same_sid && !same_pid) {
pr_err("port %hu: multiple peer responses", portnum(p));
return -1;
}
Richard Cochran
2013-03-15 18:16:12 UTC
Permalink
Post by Delio Brignoli
Any comments about this patch?
It took me a while to finally understand it, and I think it isn't
quite right. See below.
Post by Delio Brignoli
static int process_pdelay_resp(struct port *p, struct ptp_message *m)
{
if (p->peer_delay_resp) {
- if (!source_pid_eq(p->peer_delay_resp, m)) {
+ int same_pid = source_pid_eq(p->peer_delay_resp, m);
+ int same_sid = (p->peer_delay_resp->header.sequenceId ==
+ m->header.sequenceId);
First off, I found the names same_pid/sid really confusing.
Post by Delio Brignoli
+ if (same_sid && same_pid) {
This first test is okay: If this response and the last one are from
the same port, and if they are in response to the same request
(sequence number), then the remote port (or network) must have sent
multiple copies.
Post by Delio Brignoli
+ pr_err("port %hu: multiple identical peer responses", portnum(p));
+ return -1;
+ }
+ if (same_sid && !same_pid) {
This test seems wrong to me. If the response is from a different
remote port, then we know that the network is misconfigured,
regardless of whether or not the sequence numbers match or not.

Or am I missing something?
Post by Delio Brignoli
pr_err("port %hu: multiple peer responses", portnum(p));
return -1;
}
Thanks,
Richard
Delio Brignoli
2013-03-15 18:58:25 UTC
Permalink
Hello Richard,

On 3/15/13 7:16 PM, Richard Cochran wrote:

[...]
Post by Delio Brignoli
static int process_pdelay_resp(struct port *p, struct ptp_message *m)
{
if (p->peer_delay_resp) {
- if (!source_pid_eq(p->peer_delay_resp, m)) {
+ int same_pid = source_pid_eq(p->peer_delay_resp, m);
+ int same_sid = (p->peer_delay_resp->header.sequenceId ==
+ m->header.sequenceId);
First off, I found the names same_pid/sid really confusing.
Please propose an alternative you'd be happy with, I do not want to guess.

[...]
Post by Delio Brignoli
Post by Delio Brignoli
+ pr_err("port %hu: multiple identical peer responses", portnum(p));
+ return -1;
+ }
+ if (same_sid && !same_pid) {
This test seems wrong to me. If the response is from a different
remote port, then we know that the network is misconfigured,
regardless of whether or not the sequence numbers match or not.
Or am I missing something?
I added the 'same sequence number' test because p->peer_delay_resp was
not freed and set to NULL when sending a new peer delay request and I
wanted to be sure the duplicated response had been generated in response
to the current request. We now free p->peer_delay_resp when sending a
new request so I can drop the 'same_sid' part of the test.

--
Delio
Richard Cochran
2013-03-16 09:09:42 UTC
Permalink
Post by Delio Brignoli
I added the 'same sequence number' test because p->peer_delay_resp
was not freed and set to NULL when sending a new peer delay request
and I wanted to be sure the duplicated response had been generated
in response to the current request. We now free p->peer_delay_resp
when sending a new request so I can drop the 'same_sid' part of the
test.
Then I guess I applied your patch titled

Free peer delay responses and followup messages when sending a new
peer delay request

too quickly. We do need to remember the peer port ID from the last
exchange. If the network changes between our delay requests, then we
need to reset the port.

You had said in that patch,

If messages are not freed, it is possible (with purposely crafted
traffic) to trigger a peer delay calculation which will use
message's data from the previous round.

and I took your word for it, but I did not think it through to
understand what you are trying to fix. Anyhow, I don't doubt that you
found an real issue.

There are two cases to consider:

1. Multiple peer delay responses. If we receive more than one
response, this is always an error. It does not matter what the port
IDs or sequence numbers are (although you might want to
differentiate the exact kind of error).

2. Change of peer port ID. This is also an error, but it might simply
mean that the network changed, like someone unpluged one node and
plugged into another. Handling this error should result in
resetting the port, including the learned delay.

Now, after your last two patches, I think case number 2 is not being
handled any more.

One way to fix this would be to remember the peer port ID in the
'struct port'. We could then check that the reverse exchange (when the
peer sends us a delay request) is also consistent.

Thanks,
Richard
Delio Brignoli
2013-03-17 00:20:04 UTC
Permalink
Post by Richard Cochran
Post by Delio Brignoli
I added the 'same sequence number' test because p->peer_delay_resp
was not freed and set to NULL when sending a new peer delay request
and I wanted to be sure the duplicated response had been generated
in response to the current request. We now free p->peer_delay_resp
when sending a new request so I can drop the 'same_sid' part of the
test.
Then I guess I applied your patch titled
Free peer delay responses and followup messages when sending a new
peer delay request
too quickly. We do need to remember the peer port ID from the last
exchange. If the network changes between our delay requests, then we
need to reset the port.
You had said in that patch,
If messages are not freed, it is possible (with purposely crafted
traffic) to trigger a peer delay calculation which will use
message's data from the previous round.
and I took your word for it, but I did not think it through to
understand what you are trying to fix. Anyhow, I don't doubt that you
found an real issue.
When I posted the patch you mention above I didn't realize this error
condition:

if (p->peer_delay_resp) {
if (!source_pid_eq(p->peer_delay_resp, m)) {
pr_err("port %hu: multiple peer responses", portnum(p));
return -1;
}
}

would also be triggered when the peer changed between delay requests.
Post by Richard Cochran
1. Multiple peer delay responses. If we receive more than one
response, this is always an error. It does not matter what the port
IDs or sequence numbers are (although you might want to
differentiate the exact kind of error).
2. Change of peer port ID. This is also an error, but it might simply
mean that the network changed, like someone unpluged one node and
plugged into another. Handling this error should result in
resetting the port, including the learned delay.
Now, after your last two patches, I think case number 2 is not being
handled any more.
You are correct, case 2 is not being handled anymore.
Post by Richard Cochran
One way to fix this would be to remember the peer port ID in the
'struct port'. We could then check that the reverse exchange (when the
peer sends us a delay request) is also consistent.
Does the patch below look like a viable solution? If yes, I will submit
it as a standalone email. Note that the port is learning the peer's
port-id when processing either a pdelay req or a pdelay resp (whichever
happens first).

---
port.c | 22 ++++++++++++++++++++++
1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/port.c b/port.c
index 2f50888..b3e6e5a 100644
--- a/port.c
+++ b/port.c
@@ -60,6 +60,8 @@ struct port {
struct ptp_message *peer_delay_req;
struct ptp_message *peer_delay_resp;
struct ptp_message *peer_delay_fup;
+ int peer_portid_valid;
+ struct PortIdentity peer_portid;
struct {
UInteger16 announce;
UInteger16 delayreq;
@@ -679,6 +681,8 @@ static void port_nrate_initialize(struct port *p)
/* We start in the 'incapable' state. */
p->pdr_missing = ALLOWED_LOST_RESPONSES + 1;

+ p->peer_portid_valid = 0;
+
p->nrate.origin1 = tmv_zero();
p->nrate.ingress1 = tmv_zero();
p->nrate.max_count = (1 << shift);
@@ -1344,6 +1348,15 @@ static int process_pdelay_req(struct port *p,
struct ptp_message *m)
pr_info("port %hu: peer detected, switch to P2P",
portnum(p));
p->delayMechanism = DM_P2P;
}
+ if (p->peer_portid_valid) {
+ if (!pid_eq(&p->peer_portid,
&m->header.sourcePortIdentity)) {
+ pr_err("port %hu: peer port id changed",
portnum(p));
+ return -1;
+ }
+ } else {
+ p->peer_portid_valid = 1;
+ p->peer_portid = m->header.sourcePortIdentity;
+ }

rsp = msg_allocate();
if (!rsp)
@@ -1507,6 +1520,15 @@ static int process_pdelay_resp(struct port *p,
struct ptp_message *m)
pr_err("port %hu: rogue peer delay response", portnum(p));
return -1;
}
+ if (p->peer_portid_valid) {
+ if (!pid_eq(&p->peer_portid,
&m->header.sourcePortIdentity)) {
+ pr_err("port %hu: peer port id changed",
portnum(p));
+ return -1;
+ }
+ } else {
+ p->peer_portid_valid = 1;
+ p->peer_portid = m->header.sourcePortIdentity;
+ }

if (p->peer_delay_resp) {
msg_put(p->peer_delay_resp);
--
1.7.0.4
Richard Cochran
2013-03-17 17:37:09 UTC
Permalink
Post by Delio Brignoli
Does the patch below look like a viable solution? If yes, I will
submit it as a standalone email. Note that the port is learning the
peer's port-id when processing either a pdelay req or a pdelay resp
(whichever happens first).
Yes, this looks like a good approach to me.

Thanks,
Richard

Loading...