Re: [Linuxptp-devel] Adding libpmc
On Thu, 16 Apr 2020 17:06:46 +, Geva, Erez wrote: > While the Kernel is under GPL 2. > The headers and system call are under exception, so user can use the > Kernel with non GPL code. But any changes or addition to the kernel > itself should be GPL 2. This is very different. The Linux kernel is supposed to run any kind of programs under various licenses. Linux PTP is not a generic mechanism intended to run other software. [Slightly off topic: Moreover, the kernel has a strict boundary (uAPI) between its internals and the user space programs. It's so strictly defined that it does not require LGPL but instead is covered by a GPL exception. That is different to libraries. In fact, the kernel uAPI is more close to stuff like RPC or REST API than to libraries.] > The exception means that any code that is part of the LinuxPTP must > be coverd by GPL. > > But user may embedded a library in their non GPL application and > communicate with the ptp4l. > > Do you have another suggestion? Why can't those applications that use parts of linuxptp code be licensed under GPL? That seems like a win for everybody. Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] Adding libpmc
Hi Erez, On Thu, 16 Apr 2020 14:18:25 +, Geva, Erez wrote: > I see that linux PTP is under GPL 2. > > I would like to ask your permission to allow using a libpmc library > and headers needed by it under LGPL 2. Could I ask you to provide more context, please? I contributed to the Linux PTP project with the understanding it is licensed under GPL; agreeing to provide my contribution under a different license is something that I don't take lightly. You may understand that it's difficult to do such important decision based solely on a request without explanation about what project this needs, under what license, who's going to develop it, etc. Please elaborate on your plans. > As you are the copywrite holders, we need your explicit consent. I very much appreciate that you are aware of the legal implications and that you're reaching to us. Thanks, Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH 5/6] Add PHC methods for querying and configuring the pin functionality.
On Mon, 9 Mar 2020 07:16:23 -0700, Richard Cochran wrote: > But maybe that wouldn't be worst thing in the world. There is a trade > off between maintaining parallel copies of ptp_clock_caps and the > convenience of compiling the stack just once with the "future" kernel > definitions. > > Thoughts? The decision is ultimately yours but I'd prefer the copy of the struct in missing.h. Thanks, Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH 5/6] Add PHC methods for querying and configuring the pin functionality.
On Fri, 6 Mar 2020 11:23:00 -0800, Richard Cochran wrote: > +int phc_number_pins(clockid_t clkid) > +{ > + struct ptp_clock_caps caps; > + > + if (phc_get_caps(clkid, &caps)) { > + return 0; > + } > +#ifdef HAVE_PIN_SETFUNC > + return caps.n_pins; > +#else > + return 0; > +#endif > +} > + > +int phc_pin_setfunc(clockid_t clkid, struct ptp_pin_desc *desc) > +{ > + int err = -EOPNOTSUPP; > +#ifdef HAVE_PIN_SETFUNC > + err = ioctl(CLOCKID_TO_FD(clkid), PTP_PIN_SETFUNC2, desc); > + if (err) { > + fprintf(stderr, PTP_PIN_SETFUNC_FAILED "\n"); > + } > +#endif > + return err; If I'm reading the patches correctly, this would require a rebuild if the kernel is updated in order for linuxptp to use the new kernel functions. It would be better to detect this at run time instead, allowing linuxptp to use the best interface dynamically without recompiling. It seems to be doable, the old kernels return -ENOTTY for unknown commands. Thanks, Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] ptp4l port 1: bad message
On Thu, 10 Oct 2019 14:23:44 + (UTC), RAVEENDRA M via Linuxptp-devel wrote: > Any fix will be provided soon for the "bad message" errors and > protection from buggy HW? I'm afraid this is something you'll have to sort out with the hardware vendor. If they sold you the box as IEEE 1588-2008 compliant, ask them to fix the box to be really compliant (because it isn't) or to return the money. If the box is not advertised as IEEE 1588-2008 compliant, you may still try to complain; but it may very well be that it's just implementing its own proprietary protocol which is not PTP compatible. You can't expect it to be supported by a PTP daemon in such case. Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH 2/2] pmc: Support querying TLV_PORT_PROPERTIES_NP
On Mon, 16 Sep 2019 14:44:57 +, Petr Machata wrote: > So you want to change the current TLV? I guess that's reasonable, since > it is essentially an internal API. Whatever, just have a way to extend this in the future, while allowing the tools compiled today to still work after the extension. Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH 2/2] pmc: Support querying TLV_PORT_PROPERTIES_NP
On Mon, 16 Sep 2019 14:04:00 +, Petr Machata wrote: > I was actually thinking about /var/run/netns being mounted elsewhere or > some such, which would prevent "ip netns id" from working. The symbolic > names seem to be accessible from other namespaces just fine --"ip netns > exec foo ip netns exec bar bash" works-- but renaming /var/run breaks > it. /var/run/netns is a convention introduced by iproute2 and respected by many, but sadly not all, other net management systems. There is no concept of netns names in the kernel. And it is a completely different thing than netnsids. The netns mounts allow you to get a file descriptor referencing the target net name space unambiguously. Such fd can be used for many operations, most importantly to switch yourself into that net name space (see setns(2)). You can obtain the fd by other means, too, for example by opening /proc//ns/net. netnsid is a different integer. It is valid only in the net name space it was created in and references a target net name space. It can be used only in netlink operations. It is completely managed by the kernel and does not require the netns to be mounted nor /proc to be mounted. > I don't have other ideas than this. I also think that having an easy to > use way to access the interface outweighs the risks. I think proper documentation might help. Add a warning that this doesn't work across net name spaces and ensure that the API is flexible enough to allow a new field to be added in the future without breaking backwards compatibility if we ever need to start communicating also a netns identifier. Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH 2/2] pmc: Support querying TLV_PORT_PROPERTIES_NP
On Mon, 16 Sep 2019 09:56:29 +, Petr Machata wrote: > Inside the namespace you can do "ip netns id" to get the namespace that > you are in. Beware that this netnsid is only valid in the net name space that the 'ip' command ran in. It is not a global identifier and it is not valid in another net name space. In other words, ptp4l can't return a netnsid valid in the pmc net name space (without doing gross and unreliable hacks). > > Hmm. It's plausible the pmc instance wouldn't even know about the > > device, but ptp4l itself doesn't know whether to hide that info or > > not. Other way around could be that ptp4l is inside a namespace while > > pmc is not, but again it's not obvious. Every process is in exactly one net name space. There are no processes that are not in a net name space. There is a root net name space that is a bit special in some situations but it basically boils down to that it cannot be deleted. From a point of view of a process, there's nothing different about it. A net name space is a net name space. > ptp4l already has a public API to obtain the device name: the VLA > itself. There just isn't an easy way to invoke that interface. So we > don't have to concern ourselves with whether to hide the interface name > itself, that ship has sailed. If the API is so hard that it's not in use in practice, it makes a difference. > About the namespace--as an unprivileged process you can't just ask about > netns ids of random processes. So whether to allow ptp4l to give up this > information is a good question, because that might go against the > intentions of the admin of the machine. It also does not work, see above :-) > Maybe just documenting the issue is all that can be done. Could be. > I'm not sure I agree the process inside the namespace should be > disallowed from knowing it is. I'm not really well versed in network > namespaces, but looking at what "ip netns id" is doing under the hood it > looks like the kernel has interfaces to just tell you (RTM_GETNSID). Since every process is in a net name space (and exactly one net name space), it already knows by definition that it is in a name space :-) Whether referencing into other net name spaces makes sense or not, depends on the use. I'd argue that a daemon (such as ptp4l) should not mess with name spaces, as it needs the administrator to be able to run it in whatever net name space they chooses. But it can certainly query it if it is needed for proper interoperability. Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH 2/2] pmc: Support querying TLV_PORT_PROPERTIES_NP
On Fri, 13 Sep 2019 09:32:37 +, Petr Machata wrote: > I would guess the same problem applies when phc2sys uses the interface. > Why is it not an issue there? It is an issue, too, of course, but it's mostly theoretical. It won't happen in practice - usually, phc2sys will be started together with ptp4l from the same environment. pmc is different. It's not tied to the service start time, it's used by administrators and by various scripts from varying environment. While you can reasonably expect that ptp4l and phc2sys will be run in the same name space, it's not necessarily the case for pmc. Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH 2/2] pmc: Support querying TLV_PORT_PROPERTIES_NP
On Thu, 12 Sep 2019 11:06:30 +, Petr Machata wrote: > + text2str(&ppn->interface)); How does this work when net name spaces are in use? There's no guarantee that pmc is run in the same net name space where ptp4l is running. The returned interface name may correspond to a completely different interface in the pmc net name space. Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] ptp4l wrongly takes padding bytes as TLV?
On Tue, 5 Feb 2019 15:44:47 +, Vincent Li X wrote: > In our case, it's not wrong FCS or unwanted padding, but PHY replaced > original FCS with frame padding of random value. I very much doubt that. I bet the FCS was just stripped. I have yet to see a NIC that would replace FCS by a random value. Much more likely, there was (wrong and uninitialized = security problem) padding added by the sender, FCS was appended after it and stripped on the receiver side. What you see is the padding. > The thing is we should not try to decode any padding/bytes after PTP message > body as TLV, because TLV is part of PTP message and total length is > specified by the messageLength field. The description from 1588 is attached > below: > > 13.3.2.4 messageLength (UInteger16) > The value of the messageLength shall be the total number of octets that form > the PTP message. The > counted octets start with the first octet of the header and include and > terminate with the last octet of any > suffix or, if there are no suffix members with the last octet of the message > as defined in this clause. > NOTE—The message length does not include any padding bits specified in Annex > D. The only thing this says is it's wrong to add padding at the end by the sender (because that violates "the value of the messageLength shall be the total number of octets that form the PTP message"). It says nothing about what the receiver is supposed to do with a message in which messageLength is not the total number of octets. Specifically, it does not require the receiver to use messageLength; note that with correct messages it does not matter as both approaches (using messageLength vs. using real length) yield to the same result. Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] ptp4l wrongly takes padding bytes as TLV?
On Thu, 31 Jan 2019 16:28:30 +, Vincent Li X wrote: > we might also need to check again m->header.messageLength is bigger than > cnt. This might not be a bad idea; if the packet length is inconsistent with the PTP or 802.3 standard, a warning can be emitted and the packet dropped and not processed further. This would make linuxptp more robust against randomly malformed packets and would give some indication to users that the other end or intermediate network equipment is broken. Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] ptp4l wrongly takes padding bytes as TLV?
On Thu, 31 Jan 2019 07:41:38 -0800, Richard Cochran wrote: > FWIW, Wireshark shows "Bad FCS" for this frame. Please fix it at the > sender. To be fair, this is just an artifact of Wireshark guessing wrong on the packet structure. AFAIK there's no indication of the frames having FCS or not in pcap. Wireshark has to guess and when it sees the packet being 6 bytes longer than the payload and 64 bytes in total, it's natural to guess it's 2 bytes padding and 4 bytes FCS to satisfy the Ethernet minimum length requirements. While in fact, I expect that the FCS got stripped and the frame was 68 bytes. The real FCS was most likely correct. Seeing the padding bytes not being zero, I cannot resist wondering what part of its memory is the sender leaking. Could the leak be used to gather some interesting data? ;-) In any case, this behavior is wrong on several levels. And with the likely security issue present, I don't think it's worth the time to consider this hardware seriously. Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] ptp4l wrongly takes padding bytes as TLV?
On Wed, 30 Jan 2019 11:34:25 +0100, Miroslav Lichvar wrote: > Are there other vendors than Qulsar that do this? If it's a common > issue, it might need to be specified. IIRC there are few other cases > where the spec had to be adjusted to follow what existing HW was doing. The Qulsar hardware violates the PTP spec and as such, they cannot claim PTP support. If they do, it's false advertisement and it's a reason to demand fix from the vendor and if they can't deliver a fix, have the device refunded. I don't see reason why linuxptp should put hacks in place to workaround broken hardware that knowingly violates the spec. I don't even see a reason why the standard should be changed to accommodate such hardware with no real technical reasons ("we were lazy to implement the spec correctly and we just decided to violate the spec" is hardly a reason). Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH v2 4/5] sk: Added functionality for reassociate namespace
On Tue, 13 Nov 2018 10:34:20 +, Anders Selhammer wrote: > + snprintf(path, sizeof path, "/var/run/netns/%s", ns); This path is just a convention used by iproute2. There's nothing that forces a network name space to be mounted in /var/run/netns. It can be mounted elsewhere or even nowhere at all. Jiri ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH 1/8] rtnl: use ifinfomsg instead of rtgenmsg to request link info
On Mon, 3 Jul 2017 09:12:46 +0200, Richard Cochran wrote: > We can even call uname(2) to check the kernel version when bonding is > requested in the configuration. Please don't do that. Always check for the feature being present, never for a kernel version. It's common for various groups to backport newer features to older kernels; kernel version alone does not indicate anything. Thanks, Jiri -- Check out the vibrant tech community on one of the world's most engaging tech sites, Slashdot.org! http://sdm.link/slashdot ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH] Force IPv6 to IPV6 only, no ipv4 to ipv6 mapping.
On Mon, 10 Aug 2015 12:14:56 -0700, Gary E. Miller wrote: > By default, at least on Linux, opening a PF_INET6 socket also > grabs the matching IPv4 port. This patch stops that. Looks good but I think it should have more detailed description. Especially elaborate on the reasons why linuxptp needs to unconditionally deviate from the system-wide setting. I always hate when I'm debugging a problem, track it down to a particular commit and it's completely unclear why the change was introduced. Given the confusion this option creates, I think that more detailed description is in place here. Think about somebody who expects that the v6 socket listens also for v4 traffic as he's used from other programs and tries to debug why linuxptp behaves differently (I know that you stated that's only minor part of users and you're probably right but that's going to change once IPv6 becomes more common and people get used to this behavior). > Only tested on Linux. Unknown how this will work on *BSD or WinXX. I wouldn't worry about it given the amount of Linux-only interfaces linuxptp uses. Thanks, Jiri -- Jiri Benc -- ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] unknown option ntpshm_segment at line 8 in eno1 section
On Mon, 10 Aug 2015 10:32:54 -0700, Gary E. Miller wrote: > In keeping with the principla of least surprise, I would say go with the > flow and implement IPV6_V6ONLY. You could also argue that "least surprise" means to respect whatever the administrator set in the bindv6only sysctl. It's there for a reason and applications should respect the setting, unless they have a very good exceptional reason to do otherwise. Jiri -- Jiri Benc -- ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH] Add options to configure TTL/hop limit for UDP/UDP6 transports.
On Mon, 3 Aug 2015 15:49:43 +0200, Miroslav Lichvar wrote: > --- a/default.cfg > +++ b/default.cfg > @@ -60,6 +60,8 @@ ntpshm_segment 0 > transportSpecific0x0 > ptp_dst_mac 01:1B:19:00:00:00 > p2p_dst_mac 01:80:C2:00:00:0E > +udp_ttl 1 > +udp6_hop_limit 1 I don't see much reasons for having different options for IPv4 and IPv6. Just call it udp_ttl (or whatever) and use it for both IPv4 and IPv6. The fact that IPv6 standard renamed the option sucks (and one can argue it was not the best decision as it created more confusion than it solved) but both TTL and hop limit are the exactly same thing in the current networks and it doesn't make sense to distinguish them. Jiri -- Jiri Benc -- ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] unknown option ntpshm_segment at line 8 in eno1 section
On Tue, 4 Aug 2015 10:34:17 +0200, Miroslav Lichvar wrote: > When I run "ptp4l -6 -S -i ens5 -m", ss reports only IPv6 sockets for > ptp4l: > > # ss -lup | grep ptp4l > UNCONN 0 0 ::%ens5:ptp-event :::* > users:(("ptp4l",pid=5862,fd=10)) > UNCONN 0 0 ::%ens5:ptp-general :::* > users:(("ptp4l",pid=5862,fd=11)) Sadly, ss does not report whether a given socket has IPV6_V6ONLY set or not. By default (unless /proc/sys/net/ipv6/bindv6only is set), the IPv6 socket listens for both IPv6 and IPv4 connections, returning the latter as v4-mapped IPv6 address. linuxptp does not seem to set IPV6_V6ONLY, thus creating an UDP6 socket indeed prevents creating an UDP4 one on the same UDP port. Whether or not ptp4l should set IPV6_V6ONLY unconditionally needs some more thinking, but my first impression is it would need to use IPv4 multicast addresses (v4-mapped to IPv6) to send the packets to the v4 hosts and not the IPv6 multicast addresses. This doesn't seem worth the complications and IPV6_V6ONLY looks like to be appropriate here. But somebody should think it through first :-) Jiri -- Jiri Benc -- ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] ntp SHMs
[Dropping Gary and Jacob from CC, this is not related to the original topic anymore.] On Wed, 25 Feb 2015 16:15:31 +0100, Miroslav Lichvar wrote: > The man page says the clock is synchronized by another process. It's not clear what that means, though. I think the behavior of ntpshm is so special that it deserves a special chapter in the man page describing how it works, how to use it and that specifying clock sources (including the system clock and the -r parameter) has different meaning with this servo. I mean, even I am very confused by this thing, what about poor users ;-) > > From the user point of view, the shm is just another time > > source. In the code, it could be implemented as a fake clock (as you > > need at least two clocks for phc2sys to do anything) driven by this > > special servo. > > I don't follow. What would the fake clock do? > > > Requiring the user to add a random second clock for this > > to work (be it a system clock or a different PHC) is very confusing. > > It's not a random clock, it's the clock that is synchronized by the > SHM consumer, i.e. the system clock with chronyd/ntpd. SHM samples > contain timestamps from both clocks (PHC and system clock). Hmm, I see. The fake clock would not help, then. I still don't like it but I don't see a better way to do this, currently. We definitely need a better documentation. Thanks for the explanation, Jiri -- Jiri Benc -- Dive into the World of Parallel Programming The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] ntp SHMs
On Tue, 24 Feb 2015 21:33:49 +, Keller, Jacob E wrote: > I do not believe Jiri is right. I ran a similar config and it appeared > to work fine, without crazy clock jumping. Chronyd simply took the SHM > reference and tuned the system clock over time, because the ntpshm > servo presents itself to the ntp daemon. You're right and I'm not. The ntpshm servo always sets the SERVO_UNLOCKED state in the sample() callback, thus it never sets any clock. I didn't know that and I dislike that very much. This is a gross hack. Not mentioning it's not documented in the man page. Miroslav, any chance to improve this to be better understandable to users? From the user point of view, the shm is just another time source. In the code, it could be implemented as a fake clock (as you need at least two clocks for phc2sys to do anything) driven by this special servo. Requiring the user to add a random second clock for this to work (be it a system clock or a different PHC) is very confusing. This still won't allow things like a two-PHC boundary clock with NTP synchronization. For this, we'll need to be able to specify per-clock servos. The ntpshm servo then will drive only the fake clock. Jiri -- Jiri Benc -- Dive into the World of Parallel Programming The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] ntp SHMs
On Mon, 23 Feb 2015 18:48:51 -0800, Gary E. Miller wrote: > ptp4l[364.654]: port 1: UNCALIBRATED to SLAVE on MASTER_CLOCK_SELECTED > phc2sys[365.199]: port 002590.fffe.f355da-1 changed state > phc2sys[365.199]: reconfiguring after port state change > phc2sys[365.199]: selecting CLOCK_REALTIME for synchronization > phc2sys[365.199]: selecting eth0 as the master clock > phc2sys[365.199]: phc offset -70353239245525 s0 freq +0 delay 1348 > > WTF was that??? > > ptp4l[365.571]: clockcheck: clock jumped forward or running faster than > expected! > ptp4l[365.571]: master offset 70368744176888 s0 freq -9485 path delay > 58263 You are apparently running several programs that try to drive the same clock. This is going to fail, no matter what software you use. This is most likely a misconfiguration on your side, perhaps you're running multiple ptp4l instances over the same net interface. On a similar note, earlier in the thread, you mentioned that you want the realtime (system) clock to be set by other program than phc2sys. You must not tell phc2sys to drive the system clock, then, otherwise those two programs would fight each other. This means you must not pass "-r" to phc2sys, that option tells phc2sys to drive the system clock (please do read the phc2sys man page before asking more questions about this, thanks). Now, with a single interface and no system clock to sync (i.e. just phc2sys -a), there's just one clock (the internal clock of the NIC). phc2sys does synchronization of two or more clocks. If it has just one clock, it has nothing to synchronize it with and as the consequence, it does nothing. As ntpshm is implemented as a servo, it does not come into the game at all. phc2sys has nothing to synchronize, as synchronizing one clock is a no-op, and thus does nothing. Using manual mode instead of the automatic one won't change this. What's needed is implementing ntpshm to be a clock, not a servo. tl;dr: What you're trying to achieve does not work with linuxptp currently. Jiri -- Jiri Benc -- Dive into the World of Parallel Programming The Go Parallel Website, sponsored by Intel and developed in partnership with Slashdot Media, is your hub for all things parallel software development, from weekly thought leadership blogs to news, videos, case studies, tutorials and more. Take a look and join the conversation now. http://goparallel.sourceforge.net/ ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH RFC 0/4] Time stamp asymmetry correction
On Wed, 10 Dec 2014 10:03:35 +0100, Delio Brignoli wrote: > I just wanted to point out that, in the scenario above, correctly > implemented drivers and user mode applications should also track link > state changes (link speed mostly, but other factors could affect > latency) and update corrections accordingly. Drivers should probably be > given a chance to update the correction before user-mode is notified or > you’d end up with driver defaults overriding user-mode settings. You're right, that complicates things and means we'll need user space to be involved in the decision anyway. And when the user space needs to listen for link changes and act on them, there's no reason to put complicated logic into the kernel. Seems that an interface to query the driver for the current suggested correction is enough and the actual addition/subtraction should be indeed done in ptp4l. It also seems that ptp4l will need to listen for link change events. Jiri -- Jiri Benc -- Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server from Actuate! Instantly Supercharge Your Business Reports and Dashboards with Interactivity, Sharing, Native Excel Exports, App Integration & more Get technology previously reserved for billion-dollar corporations, FREE http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH RFC 0/4] Time stamp asymmetry correction
On Mon, 8 Dec 2014 14:04:56 +0100, Delio Brignoli wrote: > Yes, I was thinking it would allow to query if the driver supports this > feature and get/set current offsets. I agree. That way, with correctly implemented drivers the user will get the right correction for free but will be still able to overrule the values. What I'm thinking of is having an ethtool operation to get/set ingress/egress correction. This will be handled in the kernel (i.e. not propagated to the drivers to prevent misuse). The driver provides initial correction values (or zero if they're unknown) but user space is free to alter them or reset them to the initial values. It is obviously per-interface setting. A nice bonus is this will work with all program using the time stamping interface, not just linuxptp. This is compatible with Richard's patchset, only the config options would call the ethtool op instead of doing the correction in ptp4l. Jiri -- Jiri Benc -- Download BIRT iHub F-Type - The Free Enterprise-Grade BIRT Server from Actuate! Instantly Supercharge Your Business Reports and Dashboards with Interactivity, Sharing, Native Excel Exports, App Integration & more Get technology previously reserved for billion-dollar corporations, FREE http://pubads.g.doubleclick.net/gampad/clk?id=164703151&iu=/4140/ostg.clktrk ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH RFC V2 10/10] port: allow running a boundary clock with multiple clock devices.
On Wed, 5 Nov 2014 23:42:36 +0100, Richard Cochran wrote: > If the user has configured the appropriate option, then simply warn about > the clock device mismatch, open the port's clock device, and then go on. > > Signed-off-by: Richard Cochran > --- > port.c | 25 ++--- > 1 file changed, 22 insertions(+), 3 deletions(-) > > diff --git a/port.c b/port.c > index 2176962..95b6794 100644 > --- a/port.c > +++ b/port.c > @@ -29,6 +29,7 @@ > #include "filter.h" > #include "missing.h" > #include "msg.h" > +#include "phc.h" > #include "port.h" > #include "print.h" > #include "sk.h" > @@ -65,6 +66,7 @@ struct port { > char *name; > struct clock *clock; > clockid_t clkid; > + int max_adj; > struct transport *trp; > enum timestamp_type timestamping; > struct fdarray fda; > @@ -1952,6 +1954,8 @@ void port_close(struct port *p) > filter_destroy(p->delay_filter); > if (p->fault_fd >= 0) > close(p->fault_fd); > + if (p->max_adj) > + phc_close(p->clkid); > free(p); > } > > @@ -2463,10 +2467,25 @@ struct port *port_open(clockid_t clkid, > else if (!interface->ts_info.valid) > pr_warning("port %d: get_ts_info not supported", number); > else if (phc_index >= 0 && phc_index != interface->ts_info.phc_index) { > + char phc[32]; > + snprintf(phc, 31, "/dev/ptp%d", interface->ts_info.phc_index); > pr_err("port %d: PHC device mismatch", number); > - pr_err("port %d: /dev/ptp%d requested, but /dev/ptp%d attached", > -number, phc_index, interface->ts_info.phc_index); > - goto err_port; > + pr_err("port %d: /dev/ptp%d requested, but %s attached", > +number, phc_index, phc); > + if (!interface->boundary_clock_jbod) { > + goto err_port; > + } > + pr_warning("port %d: just a bunch of devices", number); I think this warning is enough, the previous ones ("PHC device mismatch" and "/dev/ptp%d requested, but %s attached") can be printed only when boundary_clock_jbod is not set. After all, the user is supposed to know what he's doing when enabling this. > + p->clkid = phc_open(phc); > + if (p->clkid == CLOCK_INVALID) { > + pr_err("port %d: Failed to open %s: %m", number, phc); > + goto err_port; > + } > + p->max_adj = phc_max_adj(p->clkid); > + if (!p->max_adj) { > + pr_err("port %d: clock is not adjustable", number); > + goto err_port; > + } > } > > p->pod = interface->pod; I think the servo state should be separate, too. The reference counted structure would be a good place to hold that. Jiri -- Jiri Benc -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH RFC V2 06/10] config: add a option to enable a poor man's boundary clock.
On Wed, 5 Nov 2014 23:42:32 +0100, Richard Cochran wrote: > This patch adds a configuration option that allows running a boundary clock > using "just a bunch of devices". Normally each port is probed to make sure > they all share the same PTP hardware clock, but this option will allow a > heterogeneous collection of devices, should the user really want it. > > Signed-off-by: Richard Cochran Acked-by: Jiri Benc -- Jiri Benc -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH RFC V2 08/10] phc2sys: automatic mode: synchronize all non-slave ports.
On Wed, 5 Nov 2014 23:42:34 +0100, Richard Cochran wrote: > When running a "jbod" Boundary Clock, as long as we have one slaved port, > we always want the clocks on the other ports to be synchronized, regardless > of their port state. > > Signed-off-by: Richard Cochran Acked-by: Jiri Benc -- Jiri Benc -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH RFC V2 09/10] Push the node's clock ID into the port data structure.
On Wed, 5 Nov 2014 23:42:35 +0100, Richard Cochran wrote: > This patch lets the ports (rather than the clock) remember the clock ID, > passing it back to the clock code during synchronization. This does not > represent a functional change, but rather paves the way for ports to > override the clock ID when running a "jbod" BC. > > Signed-off-by: Richard Cochran > --- > clock.c | 50 -- > clock.h |2 ++ > port.c |8 ++-- > port.h |4 +++- > 4 files changed, 35 insertions(+), 29 deletions(-) > > diff --git a/clock.c b/clock.c > index df82d2b..ca902ef 100644 > --- a/clock.c > +++ b/clock.c > @@ -72,7 +72,6 @@ struct clock_subscriber { > }; > > struct clock { > - clockid_t clkid; > struct servo *servo; > struct defaultDS dds; > struct dataset default_dataset; > @@ -268,9 +267,6 @@ void clock_destroy(struct clock *c) > } > port_close(c->uds_port); > free(c->pollfd); > - if (c->clkid != CLOCK_REALTIME) { > - phc_close(c->clkid); > - } I don't like that phc_close is not called anymore after this patch. I understand that it's not easy to do but IMHO this points out that this approach is not the best one. What about creating a reference counted structure holding clkid and reference it from struct port? This seems even better to me than my original patch splitting struct clock. Jiri -- Jiri Benc -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH] phc2sys: fix overwriting of the clock state
The reconfigure function is missing a check whether state for the given clock actually changed or not. This caused state for all unchanged ports to be zeroed. Reported-by: Richard Cochran Signed-off-by: Jiri Benc --- phc2sys.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 22eb9c965ce9..67d8a588288f 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -305,11 +305,13 @@ static void reconfigure(struct node *node) continue; } - if (c->new_state == PS_MASTER) - clock_reinit(c); + if (c->new_state) { + if (c->new_state == PS_MASTER) + clock_reinit(c); - c->state = c->new_state; - c->new_state = 0; + c->state = c->new_state; + c->new_state = 0; + } if (c->state == PS_SLAVE) { src = c; -- 1.8.3.1 -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH RFC V2 07/10] phc2sys: make automatic mode actually work.
On Wed, 5 Nov 2014 23:42:33 +0100, Richard Cochran wrote: > The reconfigure function unnecessarily clears the 'new_state' variable. > On the second and subsequent calls, this zero value incorrectly clobbers > the state of any port whose state has *not* changed. > > If, for example, a port in the MASTER state goes FAULTY, when it returns > to MASTER state, phc2sys will not synchronize it, because the SLAVE port's > state variable will have been cleared to zero, effectively erasing the > local time source. > > This patch fixes the issue by removing the assignment. > > Signed-off-by: Richard Cochran > --- > phc2sys.c |1 - > 1 file changed, 1 deletion(-) > > diff --git a/phc2sys.c b/phc2sys.c > index 22eb9c9..47ee3b8 100644 > --- a/phc2sys.c > +++ b/phc2sys.c > @@ -309,7 +309,6 @@ static void reconfigure(struct node *node) > clock_reinit(c); > > c->state = c->new_state; > - c->new_state = 0; > > if (c->state == PS_SLAVE) { > src = c; With this, we're calling clock_reinit for the MASTER state even when it did not change. The bug here is missing check for new_state == 0. I'll send a patch. Thanks, Jiri -- Jiri Benc -- Comprehensive Server Monitoring with Site24x7. Monitor 10 servers for $9/Month. Get alerted through email, SMS, voice calls or mobile push notifications. Take corrective actions from your mobile device. http://pubads.g.doubleclick.net/gampad/clk?id=154624111&iu=/4140/ostg.clktrk ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH RFC 0/3] Poor man's boundary clock
On Wed, 5 Nov 2014 19:58:32 +0100, Richard Cochran wrote: > On Wed, Nov 05, 2014 at 05:56:28PM +0100, Jiri Benc wrote: > > My plan for the next steps has been allowing ptp4l to work with > > multiple independent PHCs that would form a PTP clock (and rely on > > phc2sys to sync those PHCs). > > Doesn't my patch #2 do this? It's surely the intention. I just don't know how it works with things like servo state shared across all of the ports. > > This needs separation of struct clock into two > > structures, as some fields are per-PTP clock and some are per-PHC. > > I have a patch that does this but it needs to be rebased. > > You mean, the phc2sys 'struct clock', I guess? I really mean ptp4l. > Please post the patch, so we see what you are talking about. See below. It's very outdated, does not apply and is untested. I also don't like the structure name (although wasn't able to come up with anything better). It depends on a few more patches but those basically do some code reorganization only and should not be crucial to understanding of the intention. I'm not sure whether this patch was enough to support the boundary clock or more was needed but I remember I had the boundary clock stuff done (though untested) and I cannot find anything on top of this, so this was probably enough. > > I think this is a prerequisite to having a boundary clock that uses > > multiple PHCs, I cannot imagine how it could work without this > > separation. > > So, in the current form, what does the 'automatic' mode (I mean, -a > without -r) provide? Nothing useful? We can't do a release with half > baked stuff like that. -a without -r can indeed be considered as not much useful with the current code. I intended to send the rebased support for boundary clock shortly afterwards but as the review was much slower than I anticipated, I ran out of time allocated for this. I wouldn't call that half baked but if you want to have the boundary clock support before a new release, I can try to get some time to work on this. If it's really needed--maybe your patchset works okay, I admit I'm not 100% sure, I would have to spend some time looking into the code, my original patchset is obsolete, the patches it depended on were redesigned heavily. Thanks, Jiri commit abf3fde8ff5878b3aeab6ecafeae951ca0d6b876 Author: Jiri Benc Date: Wed Dec 4 16:35:22 2013 +0100 Support for multiple physical clocks Add support for multiple physical clocks. The "clock" term refers to the PTP node (as defined in IEEE 1588), the "physical clock" term refers to the piece of hardware that keeps time. With this patch, ptp4l still represents a single clock (= single PTP node). The ports it handles can have separate physical clocks attached, though. Obviously, such physical clocks have to be synchronized. For now, it is the responsiblity of the amdinistrator to set up phc2sys to synchronize the physical clocks in the correct direction. The ultimate plan is to modify phc2sys to do this automatically. Signed-off-by: Jiri Benc diff --git a/clock.c b/clock.c index 1bdf18445b13..e70d58f9eb84 100644 --- a/clock.c +++ b/clock.c @@ -57,9 +57,19 @@ struct clock_stats { unsigned int max_count; }; -struct clock { +struct phys_clock { + LIST_ENTRY(phys_clock) list; + struct clock *clock; clockid_t clkid; struct servo *servo; + enum servo_state servo_state; + struct clockcheck *sanity_check; + int nports; + int phc_index; +}; + +struct clock { + LIST_HEAD(phys_head, phys_clock) phys; struct defaultDS dds; struct dataset default_dataset; struct currentDS cur; @@ -79,10 +89,11 @@ struct clock { int utc_timescale; int leap_set; int kernel_leap; + int sanity_freq_limit; + enum servo_type default_servo; int utc_offset; /* grand master role */ int time_flags; /* grand master role */ int time_source; /* grand master role */ - enum servo_state servo_state; tmv_t master_offset; tmv_t path_delay; struct filter *delay_filter; @@ -96,7 +107,6 @@ struct clock { struct clock_description desc; struct clock_stats stats; int stats_interval; - struct clockcheck *sanity_check; }; struct clock the_clock; @@ -126,10 +136,6 @@ void clock_destroy(struct clock *c) } port_close(c->uds_port); free(c->pollfd); - if (c->clkid != CLOCK_REALTIME) { - phc_close(c->clkid); - } - servo_destroy(c->servo); filter_destroy(c->delay_filter); stats_destroy(c->stats.offset); stats_destroy(c->stats.freq); @@ -488,8 +494,9 @@ static void clock_update_sla
Re: [Linuxptp-devel] [PATCH RFC 0/3] Poor man's boundary clock
On Wed, 5 Nov 2014 17:34:23 +0100, Richard Cochran wrote: > I like the idea of "automatic" phc2sys, if it would only work right. It's definitely not complete yet and I'm not surprised there are bugs (although I did my best to support also future cases, it's hard to get it right without the actual code to test it). My plan for the next steps has been allowing ptp4l to work with multiple independent PHCs that would form a PTP clock (and rely on phc2sys to sync those PHCs). This needs separation of struct clock into two structures, as some fields are per-PTP clock and some are per-PHC. I have a patch that does this but it needs to be rebased. I think this is a prerequisite to having a boundary clock that uses multiple PHCs, I cannot imagine how it could work without this separation. What is not solved is the problem that Miroslav pointed out (and also pointed out to me earlier): the sync messages cannot be sent until the clock is really synced. This will need further communication between ptp4l and phc2sys. I still intend to work on this but have less time to work on linuxptp than before. Jiri -- Jiri Benc -- ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH 1/1] Restore the peer addresses in P2P mode.
On Thu, 9 Oct 2014 22:09:06 +0200, Richard Cochran wrote: > Commit ea7a7882 removed the calls to transport_peer(), inadvertently > substituting them with transport_send(), resulting in PDelay messages > being sent with an incorrect destination address. > > This patch fixes the issue by introducing peer_prepare_and_send(), > analogous to the port_prepare_and_send() function. I probably intended to pass the 'peer' argument to transport_send or something similar. Sorry for introducing the bug. Acked-by: Jiri Benc -- Jiri Benc -- Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v5 6/6] Dynamic allocation of interface config entries
Remove the limit of MAX_PORTS ports also when parsing command line arguments. Signed-off-by: Jiri Benc --- clock.c | 11 +- clock.h | 5 ++--- config.c | 72 +--- config.h | 11 ++ ptp4l.c | 41 +--- 5 files changed, 76 insertions(+), 64 deletions(-) diff --git a/clock.c b/clock.c index 76670e655725..726999e4b810 100644 --- a/clock.c +++ b/clock.c @@ -785,15 +785,16 @@ static void clock_remove_port(struct clock *c, struct port *p) port_close(p); } -struct clock *clock_create(int phc_index, struct interface *iface, int count, +struct clock *clock_create(int phc_index, struct interfaces_head *ifaces, enum timestamp_type timestamping, struct default_ds *dds, enum servo_type servo) { - int i, fadj = 0, max_adj = 0.0, sw_ts = timestamping == TS_SOFTWARE ? 1 : 0; + int fadj = 0, max_adj = 0.0, sw_ts = timestamping == TS_SOFTWARE ? 1 : 0; struct clock *c = &the_clock; struct port *p; char phc[32]; struct interface *udsif = &c->uds_interface; + struct interface *iface; struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); @@ -909,9 +910,9 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, clock_fda_changed(c); /* Create the ports. */ - for (i = 0; i < count; i++) { - if (clock_add_port(c, phc_index, timestamping, &iface[i])) { - pr_err("failed to open port %s", iface[i].name); + STAILQ_FOREACH(iface, ifaces, list) { + if (clock_add_port(c, phc_index, timestamping, iface)) { + pr_err("failed to open port %s", iface->name); return NULL; } } diff --git a/clock.h b/clock.h index 0702aca91715..a2b46be8cc1c 100644 --- a/clock.h +++ b/clock.h @@ -63,14 +63,13 @@ UInteger8 clock_class(struct clock *c); * * @param phc_indexPTP hardware clock device to use. * Pass -1 to select CLOCK_REALTIME. - * @param interfaceAn array of network interfaces. - * @param countThe number of elements in @a interfaces. + * @param ifaces A queue of network interfaces. * @param timestamping The timestamping mode for this clock. * @param dds A pointer to a default data set for the clock. * @param servoThe servo that this clock will use. * @return A pointer to the single global clock instance. */ -struct clock *clock_create(int phc_index, struct interface *iface, int count, +struct clock *clock_create(int phc_index, struct interfaces_head *ifaces, enum timestamp_type timestamping, struct default_ds *dds, enum servo_type servo); diff --git a/config.c b/config.c index 0bc85c1ac084..4cee947d1b40 100644 --- a/config.c +++ b/config.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "config.h" #include "ether.h" @@ -162,40 +163,40 @@ static enum parser_result parse_pod_setting(const char *option, static enum parser_result parse_port_setting(const char *option, const char *value, struct config *cfg, - int p) + struct interface *iface) { enum parser_result r; int val; - r = parse_pod_setting(option, value, &cfg->iface[p].pod); + r = parse_pod_setting(option, value, &iface->pod); if (r != NOT_PARSED) return r; if (!strcmp(option, "network_transport")) { if (!strcasecmp("L2", value)) - cfg->iface[p].transport = TRANS_IEEE_802_3; + iface->transport = TRANS_IEEE_802_3; else if (!strcasecmp("UDPv4", value)) - cfg->iface[p].transport = TRANS_UDP_IPV4; + iface->transport = TRANS_UDP_IPV4; else if (!strcasecmp("UDPv6", value)) - cfg->iface[p].transport = TRANS_UDP_IPV6; + iface->transport = TRANS_UDP_IPV6; else return BAD_VALUE; } else if (!strcmp(option, "delay_mechanism")) { if (!strcasecmp("Auto", value)) - cfg->iface[p].dm = DM_AUTO; + iface->dm = DM_AUTO; else if (!strcasecmp("E2E", value)) - cfg->iface[p].dm = DM_E2E; + iface->dm = DM_E2E; else if (!strcasecmp("P2P", value
[Linuxptp-devel] [PATCH v5 3/6] Dynamic port allocation
Remove the limit of MAX_PORTS ports (default 8) and keep the ports in a linked list. This allows ptp4l to be used on large machines and in the future, it will allow dynamic adding and removing of ports while ptp4l is running. For this to work, pollfd needs to be dynamically allocated. Changed pollfd handling from clock_install_fda/clock_remove_fda to notification (clock_fda_changed), where the clock will rebuild pollfd by querying all its ports. Signed-off-by: Jiri Benc --- clock.c | 234 +++- clock.h | 15 + port.c | 40 --- port.h | 16 + 4 files changed, 194 insertions(+), 111 deletions(-) diff --git a/clock.c b/clock.c index b487eef2e68d..3c6e5ce318c4 100644 --- a/clock.c +++ b/clock.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "address.h" #include "bmc.h" @@ -43,7 +44,9 @@ #define N_CLOCK_PFD (N_POLLFD + 1) /* one extra per port, for the fault timer */ #define POW2_41 ((double)(1ULL << 41)) -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +struct port { + LIST_ENTRY(port) list; +}; struct freq_estimator { tmv_t origin1; @@ -79,9 +82,9 @@ struct clock { struct ClockIdentity ptl[PATH_TRACE_MAX]; struct foreign_clock *best; struct ClockIdentity best_id; - struct port *port[MAX_PORTS]; + LIST_HEAD(ports_head, port) ports; struct port *uds_port; - struct pollfd pollfd[(MAX_PORTS + 1) * N_CLOCK_PFD]; + struct pollfd *pollfd; int nports; /* does not include the UDS port */ int free_running; int freq_est_interval; @@ -115,6 +118,8 @@ struct clock { struct clock the_clock; static void handle_state_decision_event(struct clock *c); +static int clock_resize_pollfd(struct clock *c, int new_nports); +static void clock_remove_port(struct clock *c, struct port *p); static int cid_eq(struct ClockIdentity *a, struct ClockIdentity *b) { @@ -253,12 +258,14 @@ void clock_send_notification(struct clock *c, struct ptp_message *msg, void clock_destroy(struct clock *c) { - int i; + struct port *p, *tmp; clock_flush_subscriptions(c); - for (i = 0; i < c->nports; i++) - port_close(c->port[i]); + LIST_FOREACH_SAFE(p, &c->ports, list, tmp) { + clock_remove_port(c, p); + } port_close(c->uds_port); + free(c->pollfd); if (c->clkid != CLOCK_REALTIME) { phc_close(c->clkid); } @@ -273,25 +280,25 @@ void clock_destroy(struct clock *c) msg_cleanup(); } -static int clock_fault_timeout(struct clock *c, int index, int set) +static int clock_fault_timeout(struct port *port, int set) { struct fault_interval i; if (!set) { - pr_debug("clearing fault on port %d", index + 1); - return port_set_fault_timer_lin(c->port[index], 0); + pr_debug("clearing fault on port %d", port_number(port)); + return port_set_fault_timer_lin(port, 0); } - fault_interval(c->port[index], last_fault_type(c->port[index]), &i); + fault_interval(port, last_fault_type(port), &i); if (i.type == FTMO_LINEAR_SECONDS) { pr_debug("waiting %d seconds to clear fault on port %d", -i.val, index + 1); - return port_set_fault_timer_lin(c->port[index], i.val); +i.val, port_number(port)); + return port_set_fault_timer_lin(port, i.val); } else if (i.type == FTMO_LOG2_SECONDS) { pr_debug("waiting 2^{%d} seconds to clear fault on port %d", -i.val, index + 1); - return port_set_fault_timer_log(c->port[index], 1, i.val); +i.val, port_number(port)); + return port_set_fault_timer_log(port, 1, i.val); } pr_err("Unsupported fault interval type %d", i.type); @@ -743,12 +750,45 @@ UInteger8 clock_class(struct clock *c) return c->dds.clockQuality.clockClass; } +static int clock_add_port(struct clock *c, int phc_index, + enum timestamp_type timestamping, int number, + struct interface *iface) +{ + struct port *p; + + if (clock_resize_pollfd(c, c->nports + 1)) + return -1; + p = port_open(phc_index, timestamping, number, iface, c); + if (!p) { + /* No need to shrink pollfd */ + return -1; + } + LIST_INSERT_HEAD(&c->ports, p, list); + c->nports++; + clock_fda_changed(c); + return 0; +} + +static void clock_remove_port(struct clock *c, struct port *p) +{ + /* Do not call clock_resize_pollfd, it's pointless to shrink +* t
[Linuxptp-devel] [PATCH v5 4/6] Lazy regeneration of pollfd
There's no need to regenerate pollfd multiple times during batches of port operations (like creating of the clock). Just be lazy and regenerate it only once it's needed. Signed-off-by: Jiri Benc --- clock.c | 12 +++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/clock.c b/clock.c index 3c6e5ce318c4..55a662f73128 100644 --- a/clock.c +++ b/clock.c @@ -85,6 +85,7 @@ struct clock { LIST_HEAD(ports_head, port) ports; struct port *uds_port; struct pollfd *pollfd; + int pollfd_valid; int nports; /* does not include the UDS port */ int free_running; int freq_est_interval; @@ -1002,16 +1003,24 @@ static void clock_fill_pollfd(struct pollfd *dest, struct port *p) dest[i].events = POLLIN|POLLPRI; } -void clock_fda_changed(struct clock *c) +static void clock_check_pollfd(struct clock *c) { struct port *p; struct pollfd *dest = c->pollfd; + if (c->pollfd_valid) + return; LIST_FOREACH(p, &c->ports, list) { clock_fill_pollfd(dest, p); dest += N_CLOCK_PFD; } clock_fill_pollfd(dest, c->uds_port); + c->pollfd_valid = 1; +} + +void clock_fda_changed(struct clock *c) +{ + c->pollfd_valid = 0; } static int clock_do_forward_mgmt(struct clock *c, @@ -1212,6 +1221,7 @@ int clock_poll(struct clock *c) struct pollfd *cur; struct port *p; + clock_check_pollfd(c); cnt = poll(c->pollfd, (c->nports + 1) * N_CLOCK_PFD, -1); if (cnt < 0) { if (EINTR == errno) { -- 1.8.3.1 -- ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v5 1/6] Put fault_fd into struct port
The fault timer file descriptor is a per port item, put it inside struct port where other per port file descriptors are kept. Signed-off-by: Jiri Benc --- clock.c | 18 +- port.c | 49 - port.h | 29 + 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/clock.c b/clock.c index 5b251c1498b3..6ed030531e62 100644 --- a/clock.c +++ b/clock.c @@ -82,7 +82,6 @@ struct clock { struct ClockIdentity best_id; struct port *port[CLK_N_PORTS]; struct pollfd pollfd[CLK_N_PORTS*N_CLOCK_PFD]; - int fault_fd[CLK_N_PORTS]; int nports; /* does not include the UDS port */ int free_running; int freq_est_interval; @@ -257,10 +256,8 @@ void clock_destroy(struct clock *c) int i; clock_flush_subscriptions(c); - for (i = 0; i < c->nports; i++) { + for (i = 0; i < c->nports; i++) port_close(c->port[i]); - close(c->fault_fd[i]); - } port_close(c->port[i]); /*uds*/ if (c->clkid != CLOCK_REALTIME) { phc_close(c->clkid); @@ -282,7 +279,7 @@ static int clock_fault_timeout(struct clock *c, int index, int set) if (!set) { pr_debug("clearing fault on port %d", index + 1); - return set_tmo_lin(c->fault_fd[index], 0); + return port_set_fault_timer_lin(c->port[index], 0); } fault_interval(c->port[index], last_fault_type(c->port[index]), &i); @@ -290,11 +287,11 @@ static int clock_fault_timeout(struct clock *c, int index, int set) if (i.type == FTMO_LINEAR_SECONDS) { pr_debug("waiting %d seconds to clear fault on port %d", i.val, index + 1); - return set_tmo_lin(c->fault_fd[index], i.val); + return port_set_fault_timer_lin(c->port[index], i.val); } else if (i.type == FTMO_LOG2_SECONDS) { pr_debug("waiting 2^{%d} seconds to clear fault on port %d", i.val, index + 1); - return set_tmo_log(c->fault_fd[index], 1, i.val); + return port_set_fault_timer_log(c->port[index], 1, i.val); } pr_err("Unsupported fault interval type %d", i.type); @@ -863,12 +860,7 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, pr_err("failed to open port %s", iface[i].name); return NULL; } - c->fault_fd[i] = timerfd_create(CLOCK_MONOTONIC, 0); - if (c->fault_fd[i] < 0) { - pr_err("timerfd_create failed: %m"); - return NULL; - } - c->pollfd[N_CLOCK_PFD * i + N_POLLFD].fd = c->fault_fd[i]; + c->pollfd[N_CLOCK_PFD * i + N_POLLFD].fd = port_fault_fd(c->port[i]); c->pollfd[N_CLOCK_PFD * i + N_POLLFD].events = POLLIN|POLLPRI; } diff --git a/port.c b/port.c index 080bc8e70e38..bd1b1784dc39 100644 --- a/port.c +++ b/port.c @@ -65,6 +65,7 @@ struct port { struct transport *trp; enum timestamp_type timestamping; struct fdarray fda; + int fault_fd; struct foreign_clock *best; enum syfu_state syfu; struct ptp_message *last_syncfup; @@ -193,6 +194,11 @@ int fault_interval(struct port *port, enum fault_type ft, return 0; } +int port_fault_fd(struct port *port) +{ + return port->fault_fd; +} + int set_tmo_log(int fd, unsigned int scale, int log_seconds) { struct itimerspec tmo = { @@ -253,6 +259,17 @@ int set_tmo_random(int fd, int min, int span, int log_seconds) return timerfd_settime(fd, 0, &tmo, NULL); } +int port_set_fault_timer_log(struct port *port, +unsigned int scale, int log_seconds) +{ + return set_tmo_log(port->fault_fd, scale, log_seconds); +} + +int port_set_fault_timer_lin(struct port *port, int seconds) +{ + return set_tmo_lin(port->fault_fd, seconds); +} + static void fc_clear(struct foreign_clock *fc) { struct ptp_message *m; @@ -1903,6 +1920,8 @@ void port_close(struct port *p) } transport_destroy(p->trp); filter_destroy(p->delay_filter); + if (p->fault_fd >= 0) + close(p->fault_fd); free(p); } @@ -2408,18 +2427,15 @@ struct port *port_open(int phc_index, pr_err("port %d: PHC device mismatch", number); pr_err("port %d: /dev/ptp%d requested, but /dev/ptp%d attached", number, phc_index, interface->ts_info.phc_index); - free(p); - return NULL; + goto er
[Linuxptp-devel] [PATCH v5 0/6] Dynamic port allocation
Currently, there's a limit of MAX_PORTS ports (8 by default). This patchset removes this limitation by using linked lists instead of fixed size arrays. The core patches are 3/6 and 6/6, the rest are prerequisites: patch 1/6 is moving per-port fields from struct clock to individual ports in order not to have to maintain several linked lists, patch 2/6 moves the uds port from the port array, as having it a part of linked list would make the various checks for uds port unnecessary complicated, patch 5/6 replaces the port numbering that is based on array of interface names by a per clock counter. The remaining patch, 4/6, is a follow up optimization to 3/6. Changes in v5: rebased. Addressed Richard's comments (comment in clock_remove_port, calloc and cleanup of iface config). Changes in v4: rebased on top of the current git. Changes in v3: used the BSD implementation of LIST_FOREACH_SAFE, using the system one where available. Changes in v2: rebased on top of the current git, resolved warnings reported by Richard. Jiri Benc (6): Put fault_fd into struct port Make uds port a separate field in struct clock Dynamic port allocation Lazy regeneration of pollfd Remember last used port number Dynamic allocation of interface config entries clock.c | 310 ++- clock.h | 20 ++--- config.c | 72 --- config.h | 11 ++- port.c | 89 ++ port.h | 45 ++ ptp4l.c | 41 - 7 files changed, 380 insertions(+), 208 deletions(-) -- 1.8.3.1 -- ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v5 2/6] Make uds port a separate field in struct clock
The uds port is handled specially in almost all cases, it doesn't behave like the rest of ports in the port array. Make it a standalone member of struct clock. Signed-off-by: Jiri Benc --- clock.c | 78 + 1 file changed, 45 insertions(+), 33 deletions(-) diff --git a/clock.c b/clock.c index 6ed030531e62..b487eef2e68d 100644 --- a/clock.c +++ b/clock.c @@ -40,7 +40,6 @@ #include "uds.h" #include "util.h" -#define CLK_N_PORTS (MAX_PORTS + 1) /* plus one for the UDS interface */ #define N_CLOCK_PFD (N_POLLFD + 1) /* one extra per port, for the fault timer */ #define POW2_41 ((double)(1ULL << 41)) @@ -80,8 +79,9 @@ struct clock { struct ClockIdentity ptl[PATH_TRACE_MAX]; struct foreign_clock *best; struct ClockIdentity best_id; - struct port *port[CLK_N_PORTS]; - struct pollfd pollfd[CLK_N_PORTS*N_CLOCK_PFD]; + struct port *port[MAX_PORTS]; + struct port *uds_port; + struct pollfd pollfd[(MAX_PORTS + 1) * N_CLOCK_PFD]; int nports; /* does not include the UDS port */ int free_running; int freq_est_interval; @@ -233,7 +233,7 @@ void clock_send_notification(struct clock *c, struct ptp_message *msg, { unsigned int event_pos = event / 8; uint8_t mask = 1 << (event % 8); - struct port *uds = c->port[c->nports]; + struct port *uds = c->uds_port; struct clock_subscriber *s; LIST_FOREACH(s, &c->subscribers, list) { @@ -258,7 +258,7 @@ void clock_destroy(struct clock *c) clock_flush_subscriptions(c); for (i = 0; i < c->nports; i++) port_close(c->port[i]); - port_close(c->port[i]); /*uds*/ + port_close(c->uds_port); if (c->clkid != CLOCK_REALTIME) { phc_close(c->clkid); } @@ -430,7 +430,7 @@ static int clock_management_fill_response(struct clock *c, struct port *p, respond = 1; break; case TLV_SUBSCRIBE_EVENTS_NP: - if (p != c->port[c->nports]) { + if (p != c->uds_port) { /* Only the UDS port allowed. */ break; } @@ -730,7 +730,7 @@ static int forwarding(struct clock *c, struct port *p) default: break; } - if (p == c->port[c->nports] && ps != PS_FAULTY) { /*uds*/ + if (p == c->uds_port && ps != PS_FAULTY) { return 1; } return 0; @@ -865,10 +865,10 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, } /* -* One extra port is for the UDS interface. +* Create the UDS interface. */ - c->port[i] = port_open(phc_index, timestamping, 0, udsif, c); - if (!c->port[i]) { + c->uds_port = port_open(phc_index, timestamping, 0, udsif, c); + if (!c->uds_port) { pr_err("failed to open the UDS port"); return NULL; } @@ -878,7 +878,7 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, for (i = 0; i < c->nports; i++) port_dispatch(c->port[i], EV_INITIALIZE, 0); - port_dispatch(c->port[i], EV_INITIALIZE, 0); /*uds*/ + port_dispatch(c->uds_port, EV_INITIALIZE, 0); return c; } @@ -938,10 +938,13 @@ struct ClockIdentity clock_identity(struct clock *c) void clock_install_fda(struct clock *c, struct port *p, struct fdarray fda) { int i, j, k; - for (i = 0; i < c->nports + 1; i++) { + + for (i = 0; i < c->nports; i++) { if (p == c->port[i]) break; } + if (p == c->uds_port) + i = c->nports; for (j = 0; j < N_POLLFD; j++) { k = N_CLOCK_PFD * i + j; c->pollfd[k].fd = fda.fd[j]; @@ -949,26 +952,33 @@ void clock_install_fda(struct clock *c, struct port *p, struct fdarray fda) } } +static int clock_do_forward_mgmt(struct clock *c, +struct port *in, struct port *out, +struct ptp_message *msg, int *pre_sent) +{ + if (in == out || !forwarding(c, out)) + return 0; + if (!*pre_sent) { + /* delay calling msg_pre_send until +* actually forwarding */ + msg_pre_send(msg); + *pre_sent = 1; + } + return port_forward(out, msg); +} + static void clock_forward_mgmt_msg(struct clock *c, struct port *p, struct ptp_message *msg) { int i, pdulen = 0, msg_ready = 0; - struct port *fwd; + if (forwarding(c, p) && msg->management.boundaryHops) { - for (i = 0; i < c
[Linuxptp-devel] [PATCH v5 5/6] Remember last used port number
For the ports to be truly created and removed dynamically, the last used port number has to be remembered by the clock and used for port creation. Signed-off-by: Jiri Benc --- clock.c | 9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/clock.c b/clock.c index 55a662f73128..76670e655725 100644 --- a/clock.c +++ b/clock.c @@ -87,6 +87,7 @@ struct clock { struct pollfd *pollfd; int pollfd_valid; int nports; /* does not include the UDS port */ + int last_port_number; int free_running; int freq_est_interval; int grand_master_capable; /* for 802.1AS only */ @@ -752,14 +753,15 @@ UInteger8 clock_class(struct clock *c) } static int clock_add_port(struct clock *c, int phc_index, - enum timestamp_type timestamping, int number, + enum timestamp_type timestamping, struct interface *iface) { struct port *p; if (clock_resize_pollfd(c, c->nports + 1)) return -1; - p = port_open(phc_index, timestamping, number, iface, c); + p = port_open(phc_index, timestamping, ++c->last_port_number, + iface, c); if (!p) { /* No need to shrink pollfd */ return -1; @@ -890,6 +892,7 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, LIST_INIT(&c->subscribers); LIST_INIT(&c->ports); + c->last_port_number = 0; /* * Create the UDS interface. @@ -907,7 +910,7 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, /* Create the ports. */ for (i = 0; i < count; i++) { - if (clock_add_port(c, phc_index, timestamping, i + 1, &iface[i])) { + if (clock_add_port(c, phc_index, timestamping, &iface[i])) { pr_err("failed to open port %s", iface[i].name); return NULL; } -- 1.8.3.1 -- ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH v4 3/6] Dynamic port allocation
On Sat, 19 Jul 2014 09:33:38 +0200, Richard Cochran wrote: > Sorry, just getting around to this. My general impression is that the > series looks good. Two comments below, but neither are show stoppers. Thanks. Sorry for the long delay, this time on my part because of summer vacation and all things that piled up while I was off. > > +struct port { > > + LIST_ENTRY(port) list; > > +}; > > I almost objected to this, as a matter of principle, because it is > more clean to have truly opaque objects. But on second thought, adding > a wrapper around the port is extra busy work (malloc/free) without > much benefit. So this is fine as is, but let's not get into the habit > of "friend" classes, if you know what I mean. Yes. I don't like it myself but I was not able to come up with anything nicer. The most clean way would be to define struct port_public { LIST_ENTRY(port_public) list; }; and modify struct public to look like: struct port { struct port_public public; char *name; struct clock *clock; ... }; This is highly unpractical, though. > > +static void clock_remove_port(struct clock *c, struct port *p) > > +{ > > + /* Do not bother with pollfd resizing, we don't mind if it's a bit > > +* larger than needed and clock_destroy takes care of freeing it in > > +* case we're shutting down. */ > > This comment is confusing. The only caller of clock_remove_port is > clock_destroy anyhow. Okay, fair enough. > Should there be more callers one day, then to me > it is more important to know that port_close sets all of the port's > FDs to -1. I'm not sure I follow. port_close destroys the port structure completely. As part of the port removal, number of ports is decreased, so pollfd contains always only fds for those ports that are present. No -1's for removed ports. Jiri -- Jiri Benc -- ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v4 3/6] Dynamic port allocation
Remove the limit of MAX_PORTS ports (default 8) and keep the ports in a linked list. This allows ptp4l to be used on large machines and in the future, it will allow dynamic adding and removing of ports while ptp4l is running. For this to work, pollfd needs to be dynamically allocated. Changed pollfd handling from clock_install_fda/clock_remove_fda to notification (clock_fda_changed), where the clock will rebuild pollfd by querying all its ports. Signed-off-by: Jiri Benc --- clock.c | 232 ++- clock.h | 15 +--- port.c | 40 +-- port.h | 16 + 4 files changed, 192 insertions(+), 111 deletions(-) diff --git a/clock.c b/clock.c index b561e63725e1..99b4b49d418c 100644 --- a/clock.c +++ b/clock.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "address.h" #include "bmc.h" @@ -43,7 +44,9 @@ #define N_CLOCK_PFD (N_POLLFD + 1) /* one extra per port, for the fault timer */ #define POW2_41 ((double)(1ULL << 41)) -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +struct port { + LIST_ENTRY(port) list; +}; struct freq_estimator { tmv_t origin1; @@ -79,9 +82,9 @@ struct clock { struct ClockIdentity ptl[PATH_TRACE_MAX]; struct foreign_clock *best; struct ClockIdentity best_id; - struct port *port[MAX_PORTS]; + LIST_HEAD(ports_head, port) ports; struct port *uds_port; - struct pollfd pollfd[(MAX_PORTS + 1) * N_CLOCK_PFD]; + struct pollfd *pollfd; int nports; /* does not include the UDS port */ int free_running; int freq_est_interval; @@ -115,6 +118,8 @@ struct clock { struct clock the_clock; static void handle_state_decision_event(struct clock *c); +static int clock_resize_pollfd(struct clock *c, int new_nports); +static void clock_remove_port(struct clock *c, struct port *p); static int cid_eq(struct ClockIdentity *a, struct ClockIdentity *b) { @@ -253,12 +258,14 @@ void clock_send_notification(struct clock *c, struct ptp_message *msg, void clock_destroy(struct clock *c) { - int i; + struct port *p, *tmp; clock_flush_subscriptions(c); - for (i = 0; i < c->nports; i++) - port_close(c->port[i]); + LIST_FOREACH_SAFE(p, &c->ports, list, tmp) { + clock_remove_port(c, p); + } port_close(c->uds_port); + free(c->pollfd); if (c->clkid != CLOCK_REALTIME) { phc_close(c->clkid); } @@ -273,25 +280,25 @@ void clock_destroy(struct clock *c) msg_cleanup(); } -static int clock_fault_timeout(struct clock *c, int index, int set) +static int clock_fault_timeout(struct port *port, int set) { struct fault_interval i; if (!set) { - pr_debug("clearing fault on port %d", index + 1); - return port_set_fault_timer_lin(c->port[index], 0); + pr_debug("clearing fault on port %d", port_number(port)); + return port_set_fault_timer_lin(port, 0); } - fault_interval(c->port[index], last_fault_type(c->port[index]), &i); + fault_interval(port, last_fault_type(port), &i); if (i.type == FTMO_LINEAR_SECONDS) { pr_debug("waiting %d seconds to clear fault on port %d", -i.val, index + 1); - return port_set_fault_timer_lin(c->port[index], i.val); +i.val, port_number(port)); + return port_set_fault_timer_lin(port, i.val); } else if (i.type == FTMO_LOG2_SECONDS) { pr_debug("waiting 2^{%d} seconds to clear fault on port %d", -i.val, index + 1); - return port_set_fault_timer_log(c->port[index], 1, i.val); +i.val, port_number(port)); + return port_set_fault_timer_log(port, 1, i.val); } pr_err("Unsupported fault interval type %d", i.type); @@ -743,12 +750,43 @@ UInteger8 clock_class(struct clock *c) return c->dds.clockQuality.clockClass; } +static int clock_add_port(struct clock *c, int phc_index, + enum timestamp_type timestamping, int number, + struct interface *iface) +{ + struct port *p; + + if (clock_resize_pollfd(c, c->nports + 1)) + return -1; + p = port_open(phc_index, timestamping, number, iface, c); + if (!p) { + /* No need to shrink pollfd */ + return -1; + } + LIST_INSERT_HEAD(&c->ports, p, list); + c->nports++; + clock_fda_changed(c); + return 0; +} + +static void clock_remove_port(struct clock *c, struct port *p) +{ + /* Do not bother with pollfd resizing, we don't mind if it's a bit +
[Linuxptp-devel] [PATCH v4 1/6] Put fault_fd into struct port
The fault timer file descriptor is a per port item, put it inside struct port where other per port file descriptors are kept. Signed-off-by: Jiri Benc --- clock.c | 18 +- port.c | 49 - port.h | 29 + 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/clock.c b/clock.c index ddea72f059e1..a11971efa646 100644 --- a/clock.c +++ b/clock.c @@ -82,7 +82,6 @@ struct clock { struct ClockIdentity best_id; struct port *port[CLK_N_PORTS]; struct pollfd pollfd[CLK_N_PORTS*N_CLOCK_PFD]; - int fault_fd[CLK_N_PORTS]; int nports; /* does not include the UDS port */ int free_running; int freq_est_interval; @@ -257,10 +256,8 @@ void clock_destroy(struct clock *c) int i; clock_flush_subscriptions(c); - for (i = 0; i < c->nports; i++) { + for (i = 0; i < c->nports; i++) port_close(c->port[i]); - close(c->fault_fd[i]); - } port_close(c->port[i]); /*uds*/ if (c->clkid != CLOCK_REALTIME) { phc_close(c->clkid); @@ -282,7 +279,7 @@ static int clock_fault_timeout(struct clock *c, int index, int set) if (!set) { pr_debug("clearing fault on port %d", index + 1); - return set_tmo_lin(c->fault_fd[index], 0); + return port_set_fault_timer_lin(c->port[index], 0); } fault_interval(c->port[index], last_fault_type(c->port[index]), &i); @@ -290,11 +287,11 @@ static int clock_fault_timeout(struct clock *c, int index, int set) if (i.type == FTMO_LINEAR_SECONDS) { pr_debug("waiting %d seconds to clear fault on port %d", i.val, index + 1); - return set_tmo_lin(c->fault_fd[index], i.val); + return port_set_fault_timer_lin(c->port[index], i.val); } else if (i.type == FTMO_LOG2_SECONDS) { pr_debug("waiting 2^{%d} seconds to clear fault on port %d", i.val, index + 1); - return set_tmo_log(c->fault_fd[index], 1, i.val); + return port_set_fault_timer_log(c->port[index], 1, i.val); } pr_err("Unsupported fault interval type %d", i.type); @@ -863,12 +860,7 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, pr_err("failed to open port %s", iface[i].name); return NULL; } - c->fault_fd[i] = timerfd_create(CLOCK_MONOTONIC, 0); - if (c->fault_fd[i] < 0) { - pr_err("timerfd_create failed: %m"); - return NULL; - } - c->pollfd[N_CLOCK_PFD * i + N_POLLFD].fd = c->fault_fd[i]; + c->pollfd[N_CLOCK_PFD * i + N_POLLFD].fd = port_fault_fd(c->port[i]); c->pollfd[N_CLOCK_PFD * i + N_POLLFD].events = POLLIN|POLLPRI; } diff --git a/port.c b/port.c index 63fabc103038..e2131c4d8693 100644 --- a/port.c +++ b/port.c @@ -65,6 +65,7 @@ struct port { struct transport *trp; enum timestamp_type timestamping; struct fdarray fda; + int fault_fd; struct foreign_clock *best; enum syfu_state syfu; struct ptp_message *last_syncfup; @@ -193,6 +194,11 @@ int fault_interval(struct port *port, enum fault_type ft, return 0; } +int port_fault_fd(struct port *port) +{ + return port->fault_fd; +} + int set_tmo_log(int fd, unsigned int scale, int log_seconds) { struct itimerspec tmo = { @@ -253,6 +259,17 @@ int set_tmo_random(int fd, int min, int span, int log_seconds) return timerfd_settime(fd, 0, &tmo, NULL); } +int port_set_fault_timer_log(struct port *port, +unsigned int scale, int log_seconds) +{ + return set_tmo_log(port->fault_fd, scale, log_seconds); +} + +int port_set_fault_timer_lin(struct port *port, int seconds) +{ + return set_tmo_lin(port->fault_fd, seconds); +} + static void fc_clear(struct foreign_clock *fc) { struct ptp_message *m; @@ -1903,6 +1920,8 @@ void port_close(struct port *p) } transport_destroy(p->trp); filter_destroy(p->delay_filter); + if (p->fault_fd >= 0) + close(p->fault_fd); free(p); } @@ -2408,18 +2427,15 @@ struct port *port_open(int phc_index, pr_err("port %d: PHC device mismatch", number); pr_err("port %d: /dev/ptp%d requested, but /dev/ptp%d attached", number, phc_index, interface->ts_info.phc_index); - free(p); - return NULL; + goto er
[Linuxptp-devel] [PATCH v4 0/6] Dynamic port allocation
This is a rebase of the dynamic port allocation patchset from the last year. Currently, there's a limit of MAX_PORTS ports (8 by default). This patchset removes this limitation by using linked lists instead of fixed size arrays. The core patches are 3/6 and 6/6, the rest are prerequisites: patch 1/6 is moving per-port fields from struct clock to individual ports in order not to have to maintain several linked lists, patch 2/6 moves the uds port from the port array, as having it a part of linked list would make the various checks for uds port unnecessary complicated, patch 5/6 replaces the port numbering that is based on array of interface names by a per clock counter. The remaining patch, 4/6, is a follow up optimization to 3/6. Changes in v4: rebased on top of the current git. Changes in v3: used the BSD implementation of LIST_FOREACH_SAFE, using the system one where available. Changes in v2: rebased on top of the current git, resolved warnings reported by Richard. Jiri Benc (6): Put fault_fd into struct port Make uds port a separate field in struct clock Dynamic port allocation Lazy regeneration of pollfd Remember last used port number Dynamic allocation of interface config entries clock.c | 308 ++ clock.h | 20 +--- config.c | 66 +++--- config.h | 10 +- port.c | 89 +++ port.h | 45 + ptp4l.c | 40 - 7 files changed, 368 insertions(+), 210 deletions(-) -- 1.7.6.5 -- Open source business process management suite built on Java and Eclipse Turn processes into business applications with Bonita BPM Community Edition Quickly connect people, data, and systems into organized workflows Winner of BOSSIE, CODIE, OW2 and Gartner awards http://p.sf.net/sfu/Bonitasoft ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v4 6/6] Dynamic allocation of interface config entries
Remove the limit of MAX_PORTS ports also when parsing command line arguments. Signed-off-by: Jiri Benc --- clock.c | 11 + clock.h |5 +-- config.c | 66 +++-- config.h | 10 +--- ptp4l.c | 40 5 files changed, 66 insertions(+), 66 deletions(-) diff --git a/clock.c b/clock.c index 09ea385443ab..dde508f0a17f 100644 --- a/clock.c +++ b/clock.c @@ -783,15 +783,16 @@ static void clock_remove_port(struct clock *c, struct port *p) port_close(p); } -struct clock *clock_create(int phc_index, struct interface *iface, int count, +struct clock *clock_create(int phc_index, struct interfaces_head *ifaces, enum timestamp_type timestamping, struct default_ds *dds, enum servo_type servo) { - int i, fadj = 0, max_adj = 0.0, sw_ts = timestamping == TS_SOFTWARE ? 1 : 0; + int fadj = 0, max_adj = 0.0, sw_ts = timestamping == TS_SOFTWARE ? 1 : 0; struct clock *c = &the_clock; struct port *p; char phc[32]; struct interface *udsif = &c->uds_interface; + struct interface *iface; struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); @@ -907,9 +908,9 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, clock_fda_changed(c); /* Create the ports. */ - for (i = 0; i < count; i++) { - if (clock_add_port(c, phc_index, timestamping, &iface[i])) { - pr_err("failed to open port %s", iface[i].name); + STAILQ_FOREACH(iface, ifaces, list) { + if (clock_add_port(c, phc_index, timestamping, iface)) { + pr_err("failed to open port %s", iface->name); return NULL; } } diff --git a/clock.h b/clock.h index 0702aca91715..a2b46be8cc1c 100644 --- a/clock.h +++ b/clock.h @@ -63,14 +63,13 @@ UInteger8 clock_class(struct clock *c); * * @param phc_indexPTP hardware clock device to use. * Pass -1 to select CLOCK_REALTIME. - * @param interfaceAn array of network interfaces. - * @param countThe number of elements in @a interfaces. + * @param ifaces A queue of network interfaces. * @param timestamping The timestamping mode for this clock. * @param dds A pointer to a default data set for the clock. * @param servoThe servo that this clock will use. * @return A pointer to the single global clock instance. */ -struct clock *clock_create(int phc_index, struct interface *iface, int count, +struct clock *clock_create(int phc_index, struct interfaces_head *ifaces, enum timestamp_type timestamping, struct default_ds *dds, enum servo_type servo); diff --git a/config.c b/config.c index 0bc85c1ac084..5fcd2150a88e 100644 --- a/config.c +++ b/config.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "config.h" #include "ether.h" @@ -162,40 +163,40 @@ static enum parser_result parse_pod_setting(const char *option, static enum parser_result parse_port_setting(const char *option, const char *value, struct config *cfg, - int p) + struct interface *iface) { enum parser_result r; int val; - r = parse_pod_setting(option, value, &cfg->iface[p].pod); + r = parse_pod_setting(option, value, &iface->pod); if (r != NOT_PARSED) return r; if (!strcmp(option, "network_transport")) { if (!strcasecmp("L2", value)) - cfg->iface[p].transport = TRANS_IEEE_802_3; + iface->transport = TRANS_IEEE_802_3; else if (!strcasecmp("UDPv4", value)) - cfg->iface[p].transport = TRANS_UDP_IPV4; + iface->transport = TRANS_UDP_IPV4; else if (!strcasecmp("UDPv6", value)) - cfg->iface[p].transport = TRANS_UDP_IPV6; + iface->transport = TRANS_UDP_IPV6; else return BAD_VALUE; } else if (!strcmp(option, "delay_mechanism")) { if (!strcasecmp("Auto", value)) - cfg->iface[p].dm = DM_AUTO; + iface->dm = DM_AUTO; else if (!strcasecmp("E2E", value)) - cfg->iface[p].dm = DM_E2E; + iface->dm = DM_E2E; else if (!strcasecmp("P2P&quo
[Linuxptp-devel] [PATCH v4 4/6] Lazy regeneration of pollfd
There's no need to regenerate pollfd multiple times during batches of port operations (like creating of the clock). Just be lazy and regenerate it only once it's needed. Signed-off-by: Jiri Benc --- clock.c | 12 +++- 1 files changed, 11 insertions(+), 1 deletions(-) diff --git a/clock.c b/clock.c index 99b4b49d418c..f70e87bb7239 100644 --- a/clock.c +++ b/clock.c @@ -85,6 +85,7 @@ struct clock { LIST_HEAD(ports_head, port) ports; struct port *uds_port; struct pollfd *pollfd; + int pollfd_valid; int nports; /* does not include the UDS port */ int free_running; int freq_est_interval; @@ -1000,16 +1001,24 @@ static void clock_fill_pollfd(struct pollfd *dest, struct port *p) dest[i].events = POLLIN|POLLPRI; } -void clock_fda_changed(struct clock *c) +static void clock_check_pollfd(struct clock *c) { struct port *p; struct pollfd *dest = c->pollfd; + if (c->pollfd_valid) + return; LIST_FOREACH(p, &c->ports, list) { clock_fill_pollfd(dest, p); dest += N_CLOCK_PFD; } clock_fill_pollfd(dest, c->uds_port); + c->pollfd_valid = 1; +} + +void clock_fda_changed(struct clock *c) +{ + c->pollfd_valid = 0; } static int clock_do_forward_mgmt(struct clock *c, @@ -1210,6 +1219,7 @@ int clock_poll(struct clock *c) struct pollfd *cur; struct port *p; + clock_check_pollfd(c); cnt = poll(c->pollfd, (c->nports + 1) * N_CLOCK_PFD, -1); if (cnt < 0) { if (EINTR == errno) { -- 1.7.6.5 -- Open source business process management suite built on Java and Eclipse Turn processes into business applications with Bonita BPM Community Edition Quickly connect people, data, and systems into organized workflows Winner of BOSSIE, CODIE, OW2 and Gartner awards http://p.sf.net/sfu/Bonitasoft ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v4 2/6] Make uds port a separate field in struct clock
The uds port is handled specially in almost all cases, it doesn't behave like the rest of ports in the port array. Make it a standalone member of struct clock. Signed-off-by: Jiri Benc --- clock.c | 78 -- 1 files changed, 45 insertions(+), 33 deletions(-) diff --git a/clock.c b/clock.c index a11971efa646..b561e63725e1 100644 --- a/clock.c +++ b/clock.c @@ -40,7 +40,6 @@ #include "uds.h" #include "util.h" -#define CLK_N_PORTS (MAX_PORTS + 1) /* plus one for the UDS interface */ #define N_CLOCK_PFD (N_POLLFD + 1) /* one extra per port, for the fault timer */ #define POW2_41 ((double)(1ULL << 41)) @@ -80,8 +79,9 @@ struct clock { struct ClockIdentity ptl[PATH_TRACE_MAX]; struct foreign_clock *best; struct ClockIdentity best_id; - struct port *port[CLK_N_PORTS]; - struct pollfd pollfd[CLK_N_PORTS*N_CLOCK_PFD]; + struct port *port[MAX_PORTS]; + struct port *uds_port; + struct pollfd pollfd[(MAX_PORTS + 1) * N_CLOCK_PFD]; int nports; /* does not include the UDS port */ int free_running; int freq_est_interval; @@ -233,7 +233,7 @@ void clock_send_notification(struct clock *c, struct ptp_message *msg, { unsigned int event_pos = event / 8; uint8_t mask = 1 << (event % 8); - struct port *uds = c->port[c->nports]; + struct port *uds = c->uds_port; struct clock_subscriber *s; LIST_FOREACH(s, &c->subscribers, list) { @@ -258,7 +258,7 @@ void clock_destroy(struct clock *c) clock_flush_subscriptions(c); for (i = 0; i < c->nports; i++) port_close(c->port[i]); - port_close(c->port[i]); /*uds*/ + port_close(c->uds_port); if (c->clkid != CLOCK_REALTIME) { phc_close(c->clkid); } @@ -430,7 +430,7 @@ static int clock_management_fill_response(struct clock *c, struct port *p, respond = 1; break; case SUBSCRIBE_EVENTS_NP: - if (p != c->port[c->nports]) { + if (p != c->uds_port) { /* Only the UDS port allowed. */ break; } @@ -730,7 +730,7 @@ static int forwarding(struct clock *c, struct port *p) default: break; } - if (p == c->port[c->nports] && ps != PS_FAULTY) { /*uds*/ + if (p == c->uds_port && ps != PS_FAULTY) { return 1; } return 0; @@ -865,10 +865,10 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, } /* -* One extra port is for the UDS interface. +* Create the UDS interface. */ - c->port[i] = port_open(phc_index, timestamping, 0, udsif, c); - if (!c->port[i]) { + c->uds_port = port_open(phc_index, timestamping, 0, udsif, c); + if (!c->uds_port) { pr_err("failed to open the UDS port"); return NULL; } @@ -878,7 +878,7 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, for (i = 0; i < c->nports; i++) port_dispatch(c->port[i], EV_INITIALIZE, 0); - port_dispatch(c->port[i], EV_INITIALIZE, 0); /*uds*/ + port_dispatch(c->uds_port, EV_INITIALIZE, 0); return c; } @@ -938,10 +938,13 @@ struct ClockIdentity clock_identity(struct clock *c) void clock_install_fda(struct clock *c, struct port *p, struct fdarray fda) { int i, j, k; - for (i = 0; i < c->nports + 1; i++) { + + for (i = 0; i < c->nports; i++) { if (p == c->port[i]) break; } + if (p == c->uds_port) + i = c->nports; for (j = 0; j < N_POLLFD; j++) { k = N_CLOCK_PFD * i + j; c->pollfd[k].fd = fda.fd[j]; @@ -949,26 +952,33 @@ void clock_install_fda(struct clock *c, struct port *p, struct fdarray fda) } } +static int clock_do_forward_mgmt(struct clock *c, +struct port *in, struct port *out, +struct ptp_message *msg, int *pre_sent) +{ + if (in == out || !forwarding(c, out)) + return 0; + if (!*pre_sent) { + /* delay calling msg_pre_send until +* actually forwarding */ + msg_pre_send(msg); + *pre_sent = 1; + } + return port_forward(out, msg); +} + static void clock_forward_mgmt_msg(struct clock *c, struct port *p, struct ptp_message *msg) { int i, pdulen = 0, msg_ready = 0; - struct port *fwd; + if (forwarding(c, p) && msg->management.boundaryHops) { - for (i = 0; i < c
[Linuxptp-devel] [PATCH v4 5/6] Remember last used port number
For the ports to be truly created and removed dynamically, the last used port number has to be remembered by the clock and used for port creation. Signed-off-by: Jiri Benc --- clock.c |9 ++--- 1 files changed, 6 insertions(+), 3 deletions(-) diff --git a/clock.c b/clock.c index f70e87bb7239..09ea385443ab 100644 --- a/clock.c +++ b/clock.c @@ -87,6 +87,7 @@ struct clock { struct pollfd *pollfd; int pollfd_valid; int nports; /* does not include the UDS port */ + int last_port_number; int free_running; int freq_est_interval; int grand_master_capable; /* for 802.1AS only */ @@ -752,14 +753,15 @@ UInteger8 clock_class(struct clock *c) } static int clock_add_port(struct clock *c, int phc_index, - enum timestamp_type timestamping, int number, + enum timestamp_type timestamping, struct interface *iface) { struct port *p; if (clock_resize_pollfd(c, c->nports + 1)) return -1; - p = port_open(phc_index, timestamping, number, iface, c); + p = port_open(phc_index, timestamping, ++c->last_port_number, + iface, c); if (!p) { /* No need to shrink pollfd */ return -1; @@ -888,6 +890,7 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, LIST_INIT(&c->subscribers); LIST_INIT(&c->ports); + c->last_port_number = 0; /* * Create the UDS interface. @@ -905,7 +908,7 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, /* Create the ports. */ for (i = 0; i < count; i++) { - if (clock_add_port(c, phc_index, timestamping, i + 1, &iface[i])) { + if (clock_add_port(c, phc_index, timestamping, &iface[i])) { pr_err("failed to open port %s", iface[i].name); return NULL; } -- 1.7.6.5 -- Open source business process management suite built on Java and Eclipse Turn processes into business applications with Bonita BPM Community Edition Quickly connect people, data, and systems into organized workflows Winner of BOSSIE, CODIE, OW2 and Gartner awards http://p.sf.net/sfu/Bonitasoft ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] phc2sys detecting ptp4l exit (was: Re: [PATCH v2 00/27] automatic phc2sys configuration)
On Fri, 20 Jun 2014 09:52:49 +0200, Miroslav Lichvar wrote: > I think a combination of ptp4l sending notification on exit and > phc2sys timing out when no reply is received in the pmc update > interval (1 minute) would be good enough. Except when ptp4l is killed/crashes and is restarted. That's something that wouldn't be caught by this and would create quite a messy situation, especially when it's restarted automatically by system startup scripts (e.g. systemd). > Switching to the SEQPACKET socket seems like a lot of work and it > wouldn't detect unresponsive ptp4l, which might be a useful thing to > have (the same applies to the process monitoring). I don't think that unresponsive ptp4l is a likely state. How could this happen, sans a horrible bug? Jiri -- Jiri Benc -- HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions Find What Matters Most in Your Big Data with HPCC Systems Open Source. Fast. Scalable. Simple. Ideal for Dirty Data. Leverages Graph Analysis for Fast Processing & Easy Data Exploration http://p.sf.net/sfu/hpccsystems ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] phc2sys detecting ptp4l exit (was: Re: [PATCH v2 00/27] automatic phc2sys configuration)
On Thu, 19 Jun 2014 23:01:36 +0200, Stephan Gatzka wrote: > > Better option would be asking ptp4l about its PID and monitoring it. > > That would be reliable enough but still polling, although rather cheap > > polling. > > Is ptp4l writing a PID file? If so, you can use inotify for monitoring. The problem is not detecting ptp4l start, that we can easily do using management messages. The problem is ptp4l going away, and inotify cannot help with that. Moreover, pid file won't work with multiple domains, unless you ask ptp4l about the pid file path, and then you can just ask about the pid directly. Jiri -- Jiri Benc -- HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions Find What Matters Most in Your Big Data with HPCC Systems Open Source. Fast. Scalable. Simple. Ideal for Dirty Data. Leverages Graph Analysis for Fast Processing & Easy Data Exploration http://p.sf.net/sfu/hpccsystems ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] phc2sys detecting ptp4l exit (was: Re: [PATCH v2 00/27] automatic phc2sys configuration)
On Thu, 3 Apr 2014 11:53:40 +0200, Miroslav Lichvar wrote: > As a future improvement, I think it would be nice if ptp4l sent a > notification when exiting so phc2sys could stop its synchronization > and wait until ptp4l is running again. I was thinking about how to implement this. In particular, I'd like this to be more robust and detect also ptp4l being killed. The most obvious option, detecting whether other side closed its part of the unix socket, would require changing it from SOCK_DGRAM to SOCK_SEQPACKET. Which means ptp4l would have to keep track of all uds clients, deal with accept calls, etc., and most importantly, poll these additional file descriptors. That would require quite substantial changes throughout the whole code. But then, uds is treated specially in most places, perhaps stopping pretending it's another transport wouldn't be bad. Other option is polling from phc2sys every phc_interval. That's ugly, consuming unnecessary resources and unreliable anyway. Better option would be asking ptp4l about its PID and monitoring it. That would be reliable enough but still polling, although rather cheap polling. Thoughts? Different ideas? Thanks, Jiri -- Jiri Benc -- HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions Find What Matters Most in Your Big Data with HPCC Systems Open Source. Fast. Scalable. Simple. Ideal for Dirty Data. Leverages Graph Analysis for Fast Processing & Easy Data Exploration http://p.sf.net/sfu/hpccsystems ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v3 08/15] pmc_common: easy way to set port and broadcast target
Implement pmc_target_port to set a port number, leaving clock identity unchanged, and pmc_target_all to set clock identity and port number to all 1's. Signed-off-by: Jiri Benc --- pmc_common.c | 12 +++- pmc_common.h |2 ++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/pmc_common.c b/pmc_common.c index 2c75074c8fb7..41385da45209 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -78,7 +78,7 @@ struct pmc *pmc_create(enum transport_type transport_type, const char *iface_nam goto failed; } pmc->port_identity.portNumber = 1; - memset(&pmc->target, 0xff, sizeof(pmc->target)); + pmc_target_all(pmc); pmc->boundary_hops = boundary_hops; pmc->domain_number = domain_number; @@ -325,3 +325,13 @@ int pmc_target(struct pmc *pmc, struct PortIdentity *pid) pmc->target = *pid; return 0; } + +void pmc_target_port(struct pmc *pmc, UInteger16 portNumber) +{ + pmc->target.portNumber = portNumber; +} + +void pmc_target_all(struct pmc *pmc) +{ + memset(&pmc->target, 0xff, sizeof(pmc->target)); +} diff --git a/pmc_common.h b/pmc_common.h index 9fcb51da3fd4..9adb9d1dd98b 100644 --- a/pmc_common.h +++ b/pmc_common.h @@ -41,5 +41,7 @@ int pmc_send_set_action(struct pmc *pmc, int id, void *data, int datasize); struct ptp_message *pmc_recv(struct pmc *pmc); int pmc_target(struct pmc *pmc, struct PortIdentity *pid); +void pmc_target_port(struct pmc *pmc, UInteger16 portNumber); +void pmc_target_all(struct pmc *pmc); #endif -- 1.7.6.5 -- HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions Find What Matters Most in Your Big Data with HPCC Systems Open Source. Fast. Scalable. Simple. Ideal for Dirty Data. Leverages Graph Analysis for Fast Processing & Easy Data Exploration http://p.sf.net/sfu/hpccsystems ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v3 15/15] phc2sys: reset sync offset if non PTP timescale
When grandmaster does not use PTP timescale but the previous one did, we need to reset sync offset and leap flag. Signed-off-by: Jiri Benc --- phc2sys.c |3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 76810e7c169f..76f27e938270 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -867,6 +867,9 @@ static int run_pmc_get_utc_offset(struct node *node, int timeout) node->leap = -1; else node->leap = 0; + } else { + node->sync_offset = 0; + node->leap = 0; } msg_put(msg); return 1; -- 1.7.6.5 -- HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions Find What Matters Most in Your Big Data with HPCC Systems Open Source. Fast. Scalable. Simple. Ideal for Dirty Data. Leverages Graph Analysis for Fast Processing & Easy Data Exploration http://p.sf.net/sfu/hpccsystems ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v3 10/15] phc2sys: propagate received errors
Recognize errors returned in MANAGEMENT_ERROR_STATUS TLV and return a distinct value from run_pmc in case such error is received. Signed-off-by: Jiri Benc --- phc2sys.c | 34 +++--- 1 files changed, 27 insertions(+), 7 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 3af1e51df07c..678235e92a59 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -526,9 +526,11 @@ static int is_msg_mgt(struct ptp_message *msg) if (msg->tlv_count != 1) return 0; tlv = (struct TLV *) msg->management.suffix; - if (tlv->type != TLV_MANAGEMENT) - return 0; - return 1; + if (tlv->type == TLV_MANAGEMENT) + return 1; + if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS) + return -1; + return 0; } static int get_mgt_id(struct ptp_message *msg) @@ -543,6 +545,14 @@ static void *get_mgt_data(struct ptp_message *msg) return mgt->data; } +static int get_mgt_err_id(struct ptp_message *msg) +{ + struct management_error_status *mgt; + + mgt = (struct management_error_status *)msg->management.suffix; + return mgt->id; +} + static int normalize_state(int state) { if (state != PS_MASTER && state != PS_SLAVE && @@ -630,12 +640,18 @@ static int init_pmc(struct node *node, int domain_number) return 0; } +/* Return values: + * 1: success + * 0: timeout + * -1: error reported by the other side + * -2: local error, fatal + */ static int run_pmc(struct node *node, int timeout, int ds_id, struct ptp_message **msg) { #define N_FD 1 struct pollfd pollfd[N_FD]; - int cnt; + int cnt, res; while (1) { pollfd[0].fd = pmc_get_transport_fd(node->pmc); @@ -646,7 +662,7 @@ static int run_pmc(struct node *node, int timeout, int ds_id, cnt = poll(pollfd, N_FD, timeout); if (cnt < 0) { pr_err("poll failed"); - return -1; + return -2; } if (!cnt) { /* Request the data set again in the next run. */ @@ -676,8 +692,12 @@ static int run_pmc(struct node *node, int timeout, int ds_id, if (!*msg) continue; - if (!is_msg_mgt(*msg) || - recv_subscribed(node, *msg, ds_id) || + res = is_msg_mgt(*msg); + if (res < 0 && get_mgt_err_id(*msg) == ds_id) { + node->pmc_ds_requested = 0; + return -1; + } + if (res <= 0 || recv_subscribed(node, *msg, ds_id) || get_mgt_id(*msg) != ds_id) { msg_put(*msg); *msg = NULL; -- 1.7.6.5 -- HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions Find What Matters Most in Your Big Data with HPCC Systems Open Source. Fast. Scalable. Simple. Ideal for Dirty Data. Leverages Graph Analysis for Fast Processing & Easy Data Exploration http://p.sf.net/sfu/hpccsystems ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v3 14/15] phc2sys: man page update for -a and -r options
Signed-off-by: Jiri Benc --- phc2sys.8 | 115 ++--- 1 files changed, 79 insertions(+), 36 deletions(-) diff --git a/phc2sys.8 b/phc2sys.8 index fa3ae206f3df..37a39d0ba60f 100644 --- a/phc2sys.8 +++ b/phc2sys.8 @@ -1,12 +1,17 @@ .TH PHC2SYS 8 "November 2012" "linuxptp" .SH NAME -phc2sys \- synchronize two clocks +phc2sys \- synchronize two or more clocks .SH SYNOPSIS -.B phc2sys +.B phc2sys \-a [ -.B \-wmqvx +.B \-r ] [ +.B \-r +] [ options ] +.br +.B phc2sys +[ .BI \-d " pps-device" ] [ .BI \-s " device" @@ -15,45 +20,53 @@ phc2sys \- synchronize two clocks ] [ .BI \-O " offset" ] [ -.BI \-E " servo" -] [ -.BI \-P " kp" -] [ -.BI \-I " ki" -] [ -.BI \-S " step" -] [ -.BI \-F " step" -] [ -.BI \-R " update-rate" -] [ -.BI \-N " clock-readings" -] [ -.BI \-L " freq-limit" -] [ -.BI \-u " summary-updates" -] [ -.BI \-n " domain-number" -] [ -.BI \-l " print-level" -] +.BI \-w +] [ options ] .SH DESCRIPTION .B phc2sys -is a program which synchronizes two clocks in the system. Typically, it is used -to synchronize the system clock to a PTP hardware clock (PHC), which itself is -synchronized by the +is a program which synchronizes two or more clocks in the system. Typically, +it is used to synchronize the system clock to a PTP hardware clock (PHC), +which itself is synchronized by the .BR ptp4l (8) program. -Two synchronization modes are supported, one uses a pulse per second (PPS) +With the +.B \-a +option, the clocks to synchronize are fetched from the running +.B ptp4l +daemon and the direction of synchronization automatically follows changes of +the PTP port states. + +Manual configuration is also possible. When using manual configuration, two +synchronization modes are supported, one uses a pulse per second (PPS) signal provided by the source clock and the other mode reads time from the source clock directly. Some clocks can be used in both modes, the mode which -will synchronize the slave clock with better accuracy depends on hardware and -driver implementation. +will synchronize the slave clock with better accuracy depends on hardware +and driver implementation. .SH OPTIONS .TP +.BI \-a +Read the clocks to synchronize from running +.B ptp4l +and follow changes in the port states, adjusting the synchronization +direction automatically. The system clock (CLOCK_REALTIME) is not +synchronized, unless the +.B \-r +option is also specified. +.TP +.BI \-r +Only valid together with the +.B \-a +option. Instructs +.B phc2sys +to also synchronize the system clock (CLOCK_REALTIME). By default, the +system clock is not considered as a possible time source. If you want the +system clock to be eligible to become a time source, specify the +.B \-r +option twice. +.TP .BI \-d " pps-device" Specify the PPS device of the master clock (e.g. /dev/pps0). With this option the PPS synchronization mode is used instead of the direct mode. As the PPS @@ -68,7 +81,10 @@ option the PPS signal of the master clock is enabled automatically, otherwise it has to be enabled before .B phc2sys is started (e.g. by running \f(CWecho 1 > /sys/class/ptp/ptp0/pps_enable\fP). -This option can be used only with the system clock as the slave clock. +This option can be used only with the system clock as the slave clock. Not +compatible with the +.B \-a +option. .TP .BI \-s " device" Specify the master clock by device (e.g. /dev/ptp0) or interface (e.g. eth0) or @@ -76,7 +92,9 @@ by name (e.g. CLOCK_REALTIME for the system clock). When this option is used together with the .B \-d option, the master clock is used only to correct the offset by whole number of -seconds, which cannot be fixed with PPS alone. +seconds, which cannot be fixed with PPS alone. Not compatible with the +.B \-a +option. .TP .BI \-i " interface" Performs the exact same function as @@ -89,7 +107,10 @@ should no longer be used. .TP .BI \-c " device" Specify the slave clock by device (e.g. /dev/ptp1) or interface (e.g. eth1) or -by name. The default is CLOCK_REALTIME (the system clock). +by name. The default is CLOCK_REALTIME (the system clock). Not compatible +with the +.B \-a +option. .TP .BI \-E " servo" Specify which clock servo should be used. Valid values are pi for a PI @@ -128,7 +149,10 @@ minimize the error caused by random delays in scheduling and bus utilization. The default is 5. .TP .BI \-O " offset" -Specify the offset between the slave and master times in seconds. See +Specify the offset between the slave and master times in seconds. Not +compatible with the +.B \-a +option. See .SM .B TIME SCALE USAGE below. @@ -154,7 +178,9 @@ Wait until ptp4l is in a synchronized state. If the .B \-O option is not used, also keep the offse
[Linuxptp-devel] [PATCH v3 04/15] phc2sys: store information about clocks being UTC or TAI
For now, only CLOCK_REALTIME can be UTC. This may stay this way forever but now we have a clean separation between codepaths where CLOCK_REALTIME is required and codepaths any UTC clock should take. The main motiviation behind this change is removal of sync_offset_direction. It has to be computed on the fly based on the source and destination when we have multiple clocks supported and automatic following of ptp4l state changes implemented. Signed-off-by: Jiri Benc --- phc2sys.c | 60 +--- 1 files changed, 29 insertions(+), 31 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 825d7328af15..5b1f243528ad 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -130,6 +130,7 @@ struct clock { LIST_ENTRY(clock) list; clockid_t clkid; int sysoff_supported; + int is_utc; struct servo *servo; enum servo_state servo_state; const char *source_label; @@ -146,7 +147,7 @@ struct node { int phc_readings; double phc_interval; int sync_offset; - int sync_offset_direction; + int forced_sync_offset; int leap; int leap_set; int kernel_leap; @@ -161,6 +162,15 @@ static int update_sync_offset(struct node *node); static int clock_handle_leap(struct node *node, struct clock *clock, int64_t offset, uint64_t ts, int do_leap); +static int64_t get_sync_offset(struct node *node, struct clock *dst) +{ + int direction = node->forced_sync_offset; + + if (!direction) + direction = dst->is_utc - node->master->is_utc; + return (int64_t)node->sync_offset * NS_PER_SEC * direction; +} + static void update_clock_stats(struct clock *clock, unsigned int max_count, int64_t offset, double freq, int64_t delay) { @@ -206,9 +216,7 @@ static void update_clock(struct node *node, struct clock *clock, if (clock_handle_leap(node, clock, offset, ts, do_leap)) return; - if (node->sync_offset_direction) - offset += node->sync_offset * NS_PER_SEC * - node->sync_offset_direction; + offset += get_sync_offset(node, clock); if (clock->sanity_check && clockcheck_sample(clock->sanity_check, ts)) servo_reset(clock->servo); @@ -290,7 +298,7 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd) if (src == CLOCK_INVALID) { /* The sync offset can't be applied with PPS alone. */ - node->sync_offset_direction = 0; + node->sync_offset = 0; } else { enable_pps_output(node->master->clkid); } @@ -558,15 +566,14 @@ static int clock_handle_leap(struct node *node, struct clock *clock, if (!node->leap && !do_leap) return 0; - if (clock->clkid != CLOCK_REALTIME && - node->master->clkid != CLOCK_REALTIME) + if (clock->is_utc == node->master->is_utc) return 0; /* If the system clock is the master clock, get a time stamp from it, as it is the clock which will include the leap second. */ - if (node->master->clkid == CLOCK_REALTIME) { + if (node->master->is_utc) { struct timespec tp; - if (clock_gettime(CLOCK_REALTIME, &tp)) { + if (clock_gettime(node->master->clkid, &tp)) { pr_err("failed to read clock: %m"); return -1; } @@ -575,11 +582,8 @@ static int clock_handle_leap(struct node *node, struct clock *clock, /* If the clock will be stepped, the time stamp has to be the target time. Ignore possible 1 second error in UTC offset. */ - if (clock->clkid == CLOCK_REALTIME && - clock->servo_state == SERVO_UNLOCKED) { - ts -= offset + node->sync_offset * NS_PER_SEC * - node->sync_offset_direction; - } + if (clock->is_utc && clock->servo_state == SERVO_UNLOCKED) + ts -= offset + get_sync_offset(node, clock); /* Suspend clock updates in the last second before midnight. */ if (is_utc_ambiguous(ts)) { @@ -610,10 +614,12 @@ static int clock_add(struct node *node, clockid_t clkid) c->clkid = clkid; c->servo_state = SERVO_UNLOCKED; - if (c->clkid == CLOCK_REALTIME) + if (c->clkid == CLOCK_REALTIME) { c->source_label = "sys"; - else + c->is_utc = 1; + } else { c->source_label = "phc"; + } if (node->stats_max_count > 0) { c->offset_stats = stats_create(); @@ -698,7 +704,7 @@ int main(in
[Linuxptp-devel] [PATCH v3 00/15] automatic phc2sys configuration, phc2sys part
Changes in v3: - Fixed direction of sync offset. - Fixed NULL ptr deref with manual configuration. - Added a patch that resets sync offset when grandmaster time scale changes to a non PTP timescale, e.g. when ptp4l in software time stamping mode becomes grandmaster. This bug was the reason why I haven't noticed the swapped sync offset in the previous testing. Changes in v2: - added PMC_SUBSCRIBE_DURATION constant - fixed wrong invocation of update_pmc This is the phc2sys part of the autoconfig patchset. It uses the event subscription mechanism implemented in ptp4l. The patchset is prepared to handle the "emulated boundary clock" scenario, i.e. ptp4l working over multiple PHC's. I have old patches to do that (the dynamic port allocation patchset + patchset to support multiple PHC's) which I'll rebase on top of this and post after the patchset is accepted. Jiri Benc (15): phc2sys: generalize run_pmc phc2sys: split update_sync_offset phc2sys: split clock and node phc2sys: store information about clocks being UTC or TAI phc2sys: rearrange declarations phc2sys: open devices in clock_add phc2sys: track ports pmc_common: easy way to set port and broadcast target phc2sys: event subscription phc2sys: propagate received errors phc2sys: autoconfiguration phc2sys: autoconfigure realtime clock on demand only phc2sys: check clockIdentity phc2sys: man page update for -a and -r options phc2sys: reset sync offset if non PTP timescale phc2sys.8| 115 +-- phc2sys.c| 1083 -- pmc_common.c | 12 +- pmc_common.h |2 + 4 files changed, 915 insertions(+), 297 deletions(-) -- 1.7.6.5 -- HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions Find What Matters Most in Your Big Data with HPCC Systems Open Source. Fast. Scalable. Simple. Ideal for Dirty Data. Leverages Graph Analysis for Fast Processing & Easy Data Exploration http://p.sf.net/sfu/hpccsystems ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v3 13/15] phc2sys: check clockIdentity
Make sure that we handle only one PTP clock (node). This is for an extra safety. Signed-off-by: Jiri Benc --- phc2sys.c | 44 ++-- 1 files changed, 42 insertions(+), 2 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 8890e5e1abad..76810e7c169f 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -107,6 +107,8 @@ struct node { int pmc_ds_requested; uint64_t pmc_last_update; int state_changed; + int clock_identity_set; + struct ClockIdentity clock_identity; LIST_HEAD(port_head, port) ports; LIST_HEAD(clock_head, clock) clocks; struct clock *master; @@ -612,6 +614,15 @@ static int do_loop(struct node *node, int subscriptions) return 0; /* unreachable */ } +static int check_clock_identity(struct node *node, struct ptp_message *msg) +{ + if (!node->clock_identity_set) + return 1; + return !memcmp(&node->clock_identity, + &msg->header.sourcePortIdentity.clockIdentity, + sizeof(struct ClockIdentity)); +} + static int is_msg_mgt(struct ptp_message *msg) { struct TLV *tlv; @@ -789,6 +800,12 @@ static int run_pmc(struct node *node, int timeout, int ds_id, if (!*msg) continue; + if (!check_clock_identity(node, *msg)) { + msg_put(*msg); + *msg = NULL; + continue; + } + res = is_msg_mgt(*msg); if (res < 0 && get_mgt_err_id(*msg) == ds_id) { node->pmc_ds_requested = 0; @@ -927,6 +944,24 @@ out: return res; } +static int run_pmc_clock_identity(struct node *node, int timeout) +{ + struct ptp_message *msg; + struct defaultDS *dds; + int res; + + res = run_pmc(node, timeout, DEFAULT_DATA_SET, &msg); + if (res <= 0) + return res; + + dds = (struct defaultDS *)get_mgt_data(msg); + memcpy(&node->clock_identity, &dds->clockIdentity, + sizeof(struct ClockIdentity)); + node->clock_identity_set = 1; + msg_put(msg); + return 1; +} + static void close_pmc(struct node *node) { pmc_destroy(node->pmc); @@ -943,7 +978,7 @@ static int auto_init_ports(struct node *node, int add_rt) char iface[IFNAMSIZ]; while (1) { - res = run_pmc_get_number_ports(node, 1000); + res = run_pmc_clock_identity(node, 1000); if (res < 0) return -1; if (res > 0) @@ -951,7 +986,12 @@ static int auto_init_ports(struct node *node, int add_rt) /* res == 0, timeout */ pr_notice("Waiting for ptp4l..."); } - number_ports = res; + + number_ports = run_pmc_get_number_ports(node, 1000); + if (number_ports <= 0) { + pr_err("failed to get number of ports"); + return -1; + } res = run_pmc_subscribe(node, 1000); if (res <= 0) { -- 1.7.6.5 -- HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions Find What Matters Most in Your Big Data with HPCC Systems Open Source. Fast. Scalable. Simple. Ideal for Dirty Data. Leverages Graph Analysis for Fast Processing & Easy Data Exploration http://p.sf.net/sfu/hpccsystems ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v3 06/15] phc2sys: open devices in clock_add
Do not call clock_open to open a clock device but let clock_add do that and return the newly created struct. Also, store the device (interface) name in struct clock. Signed-off-by: Jiri Benc --- phc2sys.c | 81 ++-- 1 files changed, 46 insertions(+), 35 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 3f086496ee76..cbbc583b01ac 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -67,6 +67,7 @@ struct clock { int is_utc; struct servo *servo; enum servo_state servo_state; + char *device; const char *source_label; struct stats *offset_stats; struct stats *freq_stats; @@ -129,19 +130,27 @@ static clockid_t clock_open(char *device) return clkid; } -static int clock_add(struct node *node, clockid_t clkid) +static struct clock *clock_add(struct node *node, char *device) { struct clock *c; + clockid_t clkid = CLOCK_INVALID; int max_ppb; double ppb; + if (device) { + clkid = clock_open(device); + if (clkid == CLOCK_INVALID) + return NULL; + } + c = calloc(1, sizeof(*c)); if (!c) { pr_err("failed to allocate memory for a clock"); - return -1; + return NULL; } c->clkid = clkid; c->servo_state = SERVO_UNLOCKED; + c->device = strdup(device); if (c->clkid == CLOCK_REALTIME) { c->source_label = "sys"; @@ -158,14 +167,14 @@ static int clock_add(struct node *node, clockid_t clkid) !c->freq_stats || !c->delay_stats) { pr_err("failed to create stats"); - return -1; + return NULL; } } if (node->sanity_freq_limit) { c->sanity_check = clockcheck_create(node->sanity_freq_limit); if (!c->sanity_check) { pr_err("failed to create clock check"); - return -1; + return NULL; } } @@ -181,7 +190,7 @@ static int clock_add(struct node *node, clockid_t clkid) max_ppb = phc_max_adj(c->clkid); if (!max_ppb) { pr_err("clock is not adjustable"); - return -1; + return NULL; } } @@ -194,7 +203,7 @@ static int clock_add(struct node *node, clockid_t clkid) node->phc_readings)); LIST_INSERT_HEAD(&node->clocks, c, list); - return 0; + return c; } static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, @@ -699,8 +708,8 @@ static void usage(char *progname) int main(int argc, char *argv[]) { char *progname; - clockid_t src = CLOCK_INVALID; - clockid_t dst = CLOCK_REALTIME; + char *src_name = NULL, *dst_name = NULL; + struct clock *src, *dst; int c, domain_number = 0, pps_fd = -1; int r, wait_sync = 0; int print_level = LOG_INFO, use_syslog = 1, verbose = 0; @@ -723,7 +732,7 @@ int main(int argc, char *argv[]) "c:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xl:mqvh"))) { switch (c) { case 'c': - dst = clock_open(optarg); + dst_name = strdup(optarg); break; case 'd': pps_fd = open(optarg, O_RDONLY); @@ -737,7 +746,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "'-i' has been deprecated. please use '-s' instead.\n"); case 's': - src = clock_open(optarg); + src_name = strdup(optarg); break; case 'E': if (!strcasecmp(optarg, "pi")) { @@ -826,38 +835,46 @@ int main(int argc, char *argv[]) } } - if (pps_fd < 0 && src == CLOCK_INVALID) { + if (pps_fd < 0 && !src_name) { fprintf(stderr, "valid source clock must be selected.\n"); goto bad_usage; } - if (dst == CLOCK_INVALID) { + if (!wait_sync && !node.forced_sync_offset) { fprintf(stderr, - "valid destination clock must be selected.\n"); + "time offset must be specified using -w or -O\n"); goto bad_usage; } - if (pps_fd >= 0 && dst != CLOCK_REALTIME) {
[Linuxptp-devel] [PATCH v3 12/15] phc2sys: autoconfigure realtime clock on demand only
By default, do not synchronize CLOCK_REALTIME. To do it, -r option is needed. That will only consider CLOCK_REALTIME as the destination. To consider it also as a possible time source, use -rr. Signed-off-by: Jiri Benc --- phc2sys.c | 31 --- 1 files changed, 24 insertions(+), 7 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 51213a0ae976..8890e5e1abad 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -72,6 +72,7 @@ struct clock { clockid_t clkid; int sysoff_supported; int is_utc; + int dest_only; int state; int new_state; struct servo *servo; @@ -328,10 +329,16 @@ static void reconfigure(struct node *node) node->master = NULL; return; } + if ((!src_cnt && (!rt || rt->dest_only)) || + (!dst_cnt && !rt)) { + pr_info("nothing to synchronize"); + node->master = NULL; + return; + } if (!src_cnt) { src = rt; rt->state = PS_SLAVE; - } else { + } else if (rt) { if (rt->state != PS_MASTER) { rt->state = PS_MASTER; clock_reinit(rt); @@ -926,7 +933,7 @@ static void close_pmc(struct node *node) node->pmc = NULL; } -static int auto_init_ports(struct node *node) +static int auto_init_ports(struct node *node, int add_rt) { struct port *port; struct clock *clock; @@ -981,8 +988,13 @@ static int auto_init_ports(struct node *node) } node->state_changed = 1; - if (!clock_add(node, "CLOCK_REALTIME")) - return -1; + if (add_rt) { + clock = clock_add(node, "CLOCK_REALTIME"); + if (!clock) + return -1; + if (add_rt == 1) + clock->dest_only = 1; + } /* get initial offset */ if (run_pmc_get_utc_offset(node, 1000) <= 0) { @@ -1077,6 +1089,8 @@ static void usage(char *progname) "\n" " automatic configuration:\n" " -a turn on autoconfiguration\n" + " -r synchronize system (realtime) clock\n" + "repeat -r to consider it also as a time source\n" " manual configuration:\n" " -c [dev|name] slave clock (CLOCK_REALTIME)\n" " -d [dev] master PPS device\n" @@ -1109,7 +1123,7 @@ int main(int argc, char *argv[]) char *progname; char *src_name = NULL, *dst_name = NULL; struct clock *src, *dst; - int autocfg = 0; + int autocfg = 0, rt = 0; int c, domain_number = 0, pps_fd = -1; int r, wait_sync = 0; int print_level = LOG_INFO, use_syslog = 1, verbose = 0; @@ -1129,11 +1143,14 @@ int main(int argc, char *argv[]) progname = strrchr(argv[0], '/'); progname = progname ? 1+progname : argv[0]; while (EOF != (c = getopt(argc, argv, - "ac:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xl:mqvh"))) { + "arc:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xl:mqvh"))) { switch (c) { case 'a': autocfg = 1; break; + case 'r': + rt++; + break; case 'c': dst_name = strdup(optarg); break; @@ -1263,7 +1280,7 @@ int main(int argc, char *argv[]) if (autocfg) { if (init_pmc(&node, domain_number)) return -1; - if (auto_init_ports(&node) < 0) + if (auto_init_ports(&node, rt) < 0) return -1; return do_loop(&node, 1); } -- 1.7.6.5 -- HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions Find What Matters Most in Your Big Data with HPCC Systems Open Source. Fast. Scalable. Simple. Ideal for Dirty Data. Leverages Graph Analysis for Fast Processing & Easy Data Exploration http://p.sf.net/sfu/hpccsystems ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v3 07/15] phc2sys: track ports
Add tracking of which ports have been added and to which clock they belong. Signed-off-by: Jiri Benc --- phc2sys.c | 51 +++ 1 files changed, 51 insertions(+), 0 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index cbbc583b01ac..eed2171dc6d5 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -75,6 +75,12 @@ struct clock { struct clockcheck *sanity_check; }; +struct port { + LIST_ENTRY(port) list; + unsigned int number; + struct clock *clock; +}; + struct node { unsigned int stats_max_count; int sanity_freq_limit; @@ -89,6 +95,7 @@ struct node { struct pmc *pmc; int pmc_ds_requested; uint64_t pmc_last_update; + LIST_HEAD(port_head, port) ports; LIST_HEAD(clock_head, clock) clocks; struct clock *master; }; @@ -206,6 +213,50 @@ static struct clock *clock_add(struct node *node, char *device) return c; } +static struct port *port_get(struct node *node, unsigned int number) +{ + struct port *p; + + LIST_FOREACH(p, &node->ports, list) { + if (p->number == number) + return p; + } + return NULL; +} + +static struct port *port_add(struct node *node, unsigned int number, +char *device) +{ + struct port *p; + struct clock *c = NULL, *tmp; + + p = port_get(node, number); + if (p) + return p; + /* port is a new one, look whether we have the device already on +* a different port */ + LIST_FOREACH(tmp, &node->clocks, list) { + if (!strcmp(tmp->device, device)) { + c = tmp; + break; + } + } + if (!c) { + c = clock_add(node, device); + if (!c) + return NULL; + } + p = malloc(sizeof(*p)); + if (!p) { + pr_err("failed to allocate memory for a port"); + return NULL; + } + p->number = number; + p->clock = c; + LIST_INSERT_HEAD(&node->ports, p, list); + return p; +} + static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, int64_t *offset, uint64_t *ts, int64_t *delay) { -- 1.7.6.5 -- HPCC Systems Open Source Big Data Platform from LexisNexis Risk Solutions Find What Matters Most in Your Big Data with HPCC Systems Open Source. Fast. Scalable. Simple. Ideal for Dirty Data. Leverages Graph Analysis for Fast Processing & Easy Data Exploration http://p.sf.net/sfu/hpccsystems ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v3 11/15] phc2sys: autoconfiguration
Add automatic configuration option (-a). Signed-off-by: Jiri Benc --- phc2sys.c | 278 - 1 files changed, 256 insertions(+), 22 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 678235e92a59..51213a0ae976 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -110,9 +111,11 @@ struct node { struct clock *master; }; -static int update_sync_offset(struct node *node); +static int update_pmc(struct node *node, int subscribe); static int clock_handle_leap(struct node *node, struct clock *clock, int64_t offset, uint64_t ts, int do_leap); +static int run_pmc_get_utc_offset(struct node *node, int timeout); +static void run_pmc_events(struct node *node); static clockid_t clock_open(char *device) { @@ -267,6 +270,78 @@ static struct port *port_add(struct node *node, unsigned int number, return p; } +static void clock_reinit(struct clock *clock) +{ + servo_reset(clock->servo); + clock->servo_state = SERVO_UNLOCKED; + + if (clock->offset_stats) { + stats_reset(clock->offset_stats); + stats_reset(clock->freq_stats); + stats_reset(clock->delay_stats); + } +} + +static void reconfigure(struct node *node) +{ + struct clock *c, *rt, *src; + int src_cnt = 0, dst_cnt = 0; + + pr_info("reconfiguring after port state change"); + node->state_changed = 0; + + src = rt = NULL; + LIST_FOREACH(c, &node->clocks, list) { + if (c->clkid == CLOCK_REALTIME) { + rt = c; + continue; + } + + if (c->new_state == PS_MASTER) + clock_reinit(c); + + c->state = c->new_state; + c->new_state = 0; + + if (c->state == PS_SLAVE) { + src = c; + src_cnt++; + } else if (c->state == PS_UNCALIBRATED) { + src_cnt++; + } else if (c->state == PS_MASTER) { + pr_info("selecting %s for synchronization", c->device); + dst_cnt++; + } + } + if (src_cnt > 1) { + pr_info("multiple master clocks available, postponing sync..."); + node->master = NULL; + return; + } + if (src_cnt > 0 && !src) { + pr_info("master clock not ready, waiting..."); + node->master = NULL; + return; + } + if (!src_cnt && !dst_cnt) { + pr_info("no PHC ready, waiting..."); + node->master = NULL; + return; + } + if (!src_cnt) { + src = rt; + rt->state = PS_SLAVE; + } else { + if (rt->state != PS_MASTER) { + rt->state = PS_MASTER; + clock_reinit(rt); + } + pr_info("selecting %s for synchronization", rt->device); + } + node->master = src; + pr_info("selecting %s as the master clock", src->device); +} + static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, int64_t *offset, uint64_t *ts, int64_t *delay) { @@ -465,7 +540,7 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd) pps_offset = pps_ts - phc_ts; } - do_leap = update_sync_offset(node); + do_leap = update_pmc(node, 0); if (do_leap < 0) continue; update_clock(node, clock, pps_offset, pps_ts, -1, do_leap); @@ -474,13 +549,12 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd) return 0; } -static int do_loop(struct node *node) +static int do_loop(struct node *node, int subscriptions) { struct timespec interval; struct clock *clock; uint64_t ts; int64_t offset, delay; - int src_fd = CLOCKID_TO_FD(node->master->clkid); int do_leap; interval.tv_sec = node->phc_interval; @@ -488,18 +562,34 @@ static int do_loop(struct node *node) while (1) { clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL); - do_leap = update_sync_offset(node); + do_leap = update_pmc(node, subscriptions); if (do_leap < 0) continue; + if (subscriptions) { + run_pmc_events(node); + if (node->state_changed) { +
[Linuxptp-devel] [PATCH v3 01/15] phc2sys: generalize run_pmc
Make run_pmc usable for any kind of management message. Create wrappers for waiting for ptp4l and for getting UTC offset. Signed-off-by: Jiri Benc --- phc2sys.c | 131 +++-- 1 files changed, 66 insertions(+), 65 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 5ecb602120c3..0581eb5bcb24 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -141,7 +141,6 @@ struct clock { int leap_set; int kernel_leap; struct pmc *pmc; - int pmc_ds_idx; int pmc_ds_requested; uint64_t pmc_last_update; struct clockcheck *sanity_check; @@ -390,31 +389,14 @@ static int init_pmc(struct clock *clock, int domain_number) return 0; } -static int run_pmc(struct clock *clock, int timeout, - int wait_sync, int get_utc_offset) +static int run_pmc(struct clock *clock, int timeout, int ds_id, + struct ptp_message **msg) { - struct ptp_message *msg; - struct timePropertiesDS *tds; - void *data; #define N_FD 1 struct pollfd pollfd[N_FD]; - int cnt, ds_done; -#define N_ID 2 - int ds_ids[N_ID] = { - PORT_DATA_SET, - TIME_PROPERTIES_DATA_SET - }; - - while (clock->pmc_ds_idx < N_ID) { - /* Check if the data set is really needed. */ - if ((ds_ids[clock->pmc_ds_idx] == PORT_DATA_SET && -!wait_sync) || - (ds_ids[clock->pmc_ds_idx] == TIME_PROPERTIES_DATA_SET && -!get_utc_offset)) { - clock->pmc_ds_idx++; - continue; - } + int cnt; + while (1) { pollfd[0].fd = pmc_get_transport_fd(clock->pmc); pollfd[0].events = POLLIN|POLLPRI; if (!clock->pmc_ds_requested) @@ -434,62 +416,76 @@ static int run_pmc(struct clock *clock, int timeout, /* Send a new request if there are no pending messages. */ if ((pollfd[0].revents & POLLOUT) && !(pollfd[0].revents & (POLLIN|POLLPRI))) { - pmc_send_get_action(clock->pmc, - ds_ids[clock->pmc_ds_idx]); + pmc_send_get_action(clock->pmc, ds_id); clock->pmc_ds_requested = 1; } if (!(pollfd[0].revents & (POLLIN|POLLPRI))) continue; - msg = pmc_recv(clock->pmc); + *msg = pmc_recv(clock->pmc); - if (!msg) + if (!*msg) continue; - if (!is_msg_mgt(msg) || - get_mgt_id(msg) != ds_ids[clock->pmc_ds_idx]) { - msg_put(msg); + if (!is_msg_mgt(*msg) || + get_mgt_id(*msg) != ds_id) { + msg_put(*msg); + *msg = NULL; continue; } + clock->pmc_ds_requested = 0; + return 1; + } +} - data = get_mgt_data(msg); - ds_done = 0; - - switch (get_mgt_id(msg)) { - case PORT_DATA_SET: - switch (((struct portDS *)data)->portState) { - case PS_MASTER: - case PS_SLAVE: - ds_done = 1; - break; - } +static int run_pmc_wait_sync(struct clock *clock, int timeout) +{ + struct ptp_message *msg; + int res; + void *data; + Enumeration8 portState; - break; - case TIME_PROPERTIES_DATA_SET: - tds = (struct timePropertiesDS *)data; - if (tds->flags & PTP_TIMESCALE) { - clock->sync_offset = tds->currentUtcOffset; - if (tds->flags & LEAP_61) - clock->leap = 1; - else if (tds->flags & LEAP_59) - clock->leap = -1; - else - clock->leap = 0; - } - ds_done = 1; - break; - } + while (1) { + res = run_pmc(clock, timeout, PORT_DATA_SET, &msg); + if (res <= 0) + return res; - if (ds_done) { - /* Proceed with the next data set. */ - clock->pmc_ds_idx++; - clock->pmc_ds_requested = 0; - } + data = get_mgt_data(msg); + port
[Linuxptp-devel] [PATCH v3 02/15] phc2sys: split update_sync_offset
Split the generic (global) part of update_sync_offset and the part that affects individual clocks. This is in preparation for phc2sys handling synchronization of more clocks. Signed-off-by: Jiri Benc --- phc2sys.c | 71 +++- 1 files changed, 55 insertions(+), 16 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 0581eb5bcb24..19dce45964eb 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -60,7 +60,9 @@ #define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC) struct clock; -static int update_sync_offset(struct clock *clock, int64_t offset, uint64_t ts); +static int update_sync_offset(struct clock *clock); +static int clock_handle_leap(struct clock *clock, clockid_t src, +int64_t offset, uint64_t ts, int do_leap); static clockid_t clock_open(char *device) { @@ -181,13 +183,14 @@ static void update_clock_stats(struct clock *clock, stats_reset(clock->delay_stats); } -static void update_clock(struct clock *clock, -int64_t offset, uint64_t ts, int64_t delay) +static void update_clock(struct clock *clock, clockid_t src, +int64_t offset, uint64_t ts, int64_t delay, +int do_leap) { enum servo_state state; double ppb; - if (update_sync_offset(clock, offset, ts)) + if (clock_handle_leap(clock, src, offset, ts, do_leap)) return; if (clock->sync_offset_direction) @@ -268,6 +271,7 @@ static int do_pps_loop(struct clock *clock, int fd, { int64_t pps_offset, phc_offset, phc_delay; uint64_t pps_ts, phc_ts; + int do_leap; clock->source_label = "pps"; @@ -304,7 +308,10 @@ static int do_pps_loop(struct clock *clock, int fd, pps_offset = pps_ts - phc_ts; } - update_clock(clock, pps_offset, pps_ts, -1); + do_leap = update_sync_offset(clock); + if (do_leap <= 0) + continue; + update_clock(clock, src, pps_offset, pps_ts, -1, do_leap); } close(fd); return 0; @@ -316,6 +323,7 @@ static int do_sysoff_loop(struct clock *clock, clockid_t src, uint64_t ts; int64_t offset, delay; int err = 0, fd = CLOCKID_TO_FD(src); + int do_leap; clock->source_label = "sys"; @@ -325,7 +333,10 @@ static int do_sysoff_loop(struct clock *clock, clockid_t src, err = -1; break; } - update_clock(clock, offset, ts, delay); + do_leap = update_sync_offset(clock); + if (do_leap <= 0) + continue; + update_clock(clock, src, offset, ts, delay, do_leap); } return err; } @@ -335,6 +346,7 @@ static int do_phc_loop(struct clock *clock, clockid_t src, { uint64_t ts; int64_t offset, delay; + int do_leap; clock->source_label = "phc"; @@ -344,7 +356,10 @@ static int do_phc_loop(struct clock *clock, clockid_t src, &offset, &ts, &delay)) { continue; } - update_clock(clock, offset, ts, delay); + do_leap = update_sync_offset(clock); + if (do_leap <= 0) + continue; + update_clock(clock, src, offset, ts, delay, do_leap); } return 0; } @@ -495,10 +510,19 @@ static void close_pmc(struct clock *clock) clock->pmc = NULL; } -static int update_sync_offset(struct clock *clock, int64_t offset, uint64_t ts) +/* Returns: -1 in case of error, 0 for normal sync, 1 to leap clock */ +static int update_sync_offset(struct clock *clock) { + struct timespec tp; + uint64_t ts; int clock_leap; + if (clock_gettime(CLOCK_REALTIME, &tp)) { + pr_err("failed to read clock: %m"); + return -1; + } + ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec; + if (clock->pmc && !(ts > clock->pmc_last_update && ts - clock->pmc_last_update < PMC_UPDATE_INTERVAL)) { @@ -511,9 +535,28 @@ static int update_sync_offset(struct clock *clock, int64_t offset, uint64_t ts) if (!clock->leap && !clock->leap_set) return 0; + clock_leap = leap_second_status(ts, clock->leap_set, + &clock->leap, &clock->sync_offset); + if (clock->leap_set != clock_leap) { + clock->leap_set = clock_leap; + return 1; + } + return 0; +} + +/* Returns: non-zero to skip clock update */ +static int clock_handle_leap(struct clock *clock, clockid_t src, +int64_t o
[Linuxptp-devel] [PATCH v3 03/15] phc2sys: split clock and node
Split members that apply to all synchronized clocks and members that apply to an individual clock. Keep all clocks in a list, with a pointer to the source clock. This will allow to support multiple clocks synchronization. Signed-off-by: Jiri Benc --- phc2sys.c | 397 +--- 1 files changed, 218 insertions(+), 179 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 19dce45964eb..825d7328af15 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -60,9 +61,6 @@ #define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC) struct clock; -static int update_sync_offset(struct clock *clock); -static int clock_handle_leap(struct clock *clock, clockid_t src, -int64_t offset, uint64_t ts, int do_leap); static clockid_t clock_open(char *device) { @@ -129,14 +127,24 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, } struct clock { + LIST_ENTRY(clock) list; clockid_t clkid; + int sysoff_supported; struct servo *servo; enum servo_state servo_state; const char *source_label; struct stats *offset_stats; struct stats *freq_stats; struct stats *delay_stats; + struct clockcheck *sanity_check; +}; + +struct node { unsigned int stats_max_count; + int sanity_freq_limit; + enum servo_type servo_type; + int phc_readings; + double phc_interval; int sync_offset; int sync_offset_direction; int leap; @@ -145,10 +153,15 @@ struct clock { struct pmc *pmc; int pmc_ds_requested; uint64_t pmc_last_update; - struct clockcheck *sanity_check; + LIST_HEAD(clock_head, clock) clocks; + struct clock *master; }; -static void update_clock_stats(struct clock *clock, +static int update_sync_offset(struct node *node); +static int clock_handle_leap(struct node *node, struct clock *clock, +int64_t offset, uint64_t ts, int do_leap); + +static void update_clock_stats(struct clock *clock, unsigned int max_count, int64_t offset, double freq, int64_t delay) { struct stats_result offset_stats, freq_stats, delay_stats; @@ -158,7 +171,7 @@ static void update_clock_stats(struct clock *clock, if (delay >= 0) stats_add_value(clock->delay_stats, delay); - if (stats_get_num_values(clock->offset_stats) < clock->stats_max_count) + if (stats_get_num_values(clock->offset_stats) < max_count) return; stats_get_result(clock->offset_stats, &offset_stats); @@ -183,19 +196,19 @@ static void update_clock_stats(struct clock *clock, stats_reset(clock->delay_stats); } -static void update_clock(struct clock *clock, clockid_t src, +static void update_clock(struct node *node, struct clock *clock, int64_t offset, uint64_t ts, int64_t delay, int do_leap) { enum servo_state state; double ppb; - if (clock_handle_leap(clock, src, offset, ts, do_leap)) + if (clock_handle_leap(node, clock, offset, ts, do_leap)) return; - if (clock->sync_offset_direction) - offset += clock->sync_offset * NS_PER_SEC * - clock->sync_offset_direction; + if (node->sync_offset_direction) + offset += node->sync_offset * NS_PER_SEC * + node->sync_offset_direction; if (clock->sanity_check && clockcheck_sample(clock->sanity_check, ts)) servo_reset(clock->servo); @@ -221,15 +234,15 @@ static void update_clock(struct clock *clock, clockid_t src, } if (clock->offset_stats) { - update_clock_stats(clock, offset, ppb, delay); + update_clock_stats(clock, node->stats_max_count, offset, ppb, delay); } else { if (delay >= 0) { pr_info("%s offset %9" PRId64 " s%d freq %+7.0f " "delay %6" PRId64, - clock->source_label, offset, state, ppb, delay); + node->master->source_label, offset, state, ppb, delay); } else { pr_info("%s offset %9" PRId64 " s%d freq %+7.0f", - clock->source_label, offset, state, ppb); + node->master->source_label, offset, state, ppb); } } } @@ -266,20 +279,20 @@ static int read_pps(int fd, int64_t *offset, uint64_t *ts) return 1; } -static int do_pps_loop(struct clock *clock, int fd, - clockid_t src, int n_readings)
[Linuxptp-devel] [PATCH v3 05/15] phc2sys: rearrange declarations
This just moves code around to have related functions together and forward declaration at the beginning of the file. No code changes. Signed-off-by: Jiri Benc --- phc2sys.c | 208 ++--- 1 files changed, 103 insertions(+), 105 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 5b1f243528ad..3f086496ee76 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -60,7 +60,41 @@ #define PHC_PPS_OFFSET_LIMIT 1000 #define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC) -struct clock; +struct clock { + LIST_ENTRY(clock) list; + clockid_t clkid; + int sysoff_supported; + int is_utc; + struct servo *servo; + enum servo_state servo_state; + const char *source_label; + struct stats *offset_stats; + struct stats *freq_stats; + struct stats *delay_stats; + struct clockcheck *sanity_check; +}; + +struct node { + unsigned int stats_max_count; + int sanity_freq_limit; + enum servo_type servo_type; + int phc_readings; + double phc_interval; + int sync_offset; + int forced_sync_offset; + int leap; + int leap_set; + int kernel_leap; + struct pmc *pmc; + int pmc_ds_requested; + uint64_t pmc_last_update; + LIST_HEAD(clock_head, clock) clocks; + struct clock *master; +}; + +static int update_sync_offset(struct node *node); +static int clock_handle_leap(struct node *node, struct clock *clock, +int64_t offset, uint64_t ts, int do_leap); static clockid_t clock_open(char *device) { @@ -95,6 +129,74 @@ static clockid_t clock_open(char *device) return clkid; } +static int clock_add(struct node *node, clockid_t clkid) +{ + struct clock *c; + int max_ppb; + double ppb; + + c = calloc(1, sizeof(*c)); + if (!c) { + pr_err("failed to allocate memory for a clock"); + return -1; + } + c->clkid = clkid; + c->servo_state = SERVO_UNLOCKED; + + if (c->clkid == CLOCK_REALTIME) { + c->source_label = "sys"; + c->is_utc = 1; + } else { + c->source_label = "phc"; + } + + if (node->stats_max_count > 0) { + c->offset_stats = stats_create(); + c->freq_stats = stats_create(); + c->delay_stats = stats_create(); + if (!c->offset_stats || + !c->freq_stats || + !c->delay_stats) { + pr_err("failed to create stats"); + return -1; + } + } + if (node->sanity_freq_limit) { + c->sanity_check = clockcheck_create(node->sanity_freq_limit); + if (!c->sanity_check) { + pr_err("failed to create clock check"); + return -1; + } + } + + clockadj_init(c->clkid); + ppb = clockadj_get_freq(c->clkid); + /* The reading may silently fail and return 0, reset the frequency to + make sure ppb is the actual frequency of the clock. */ + clockadj_set_freq(c->clkid, ppb); + if (c->clkid == CLOCK_REALTIME) { + sysclk_set_leap(0); + max_ppb = sysclk_max_freq(); + } else { + max_ppb = phc_max_adj(c->clkid); + if (!max_ppb) { + pr_err("clock is not adjustable"); + return -1; + } + } + + c->servo = servo_create(node->servo_type, -ppb, max_ppb, 0); + servo_sync_interval(c->servo, node->phc_interval); + + if (clkid != CLOCK_REALTIME) + c->sysoff_supported = (SYSOFF_SUPPORTED == + sysoff_probe(CLOCKID_TO_FD(clkid), + node->phc_readings)); + + LIST_INSERT_HEAD(&node->clocks, c, list); + return 0; +} + static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, int64_t *offset, uint64_t *ts, int64_t *delay) { @@ -126,42 +228,6 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, return 1; } -struct clock { - LIST_ENTRY(clock) list; - clockid_t clkid; - int sysoff_supported; - int is_utc; - struct servo *servo; - enum servo_state servo_state; - const char *source_label; - struct stats *offset_stats; - struct stats *freq_stats; - struct stats *delay_stats; - struct clockcheck *sanity_check; -}; - -struct node { - unsigned int stats_max_count; - int sanity_freq_limit; - enum servo_type servo_type; - int phc_readings; - double phc_interval; - int sync_offs
[Linuxptp-devel] [PATCH v3 09/15] phc2sys: event subscription
Add support for subscribing to events (run_pmc_subscribe) and receiving and handling of received events (run_pmc_events). Add initial support for port status changes. Signed-off-by: Jiri Benc --- phc2sys.c | 116 +++- 1 files changed, 114 insertions(+), 2 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index eed2171dc6d5..3af1e51df07c 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -41,6 +41,7 @@ #include "ds.h" #include "fsm.h" #include "missing.h" +#include "notification.h" #include "phc.h" #include "pi.h" #include "pmc_common.h" @@ -59,12 +60,19 @@ #define PHC_PPS_OFFSET_LIMIT 1000 #define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC) +#define PMC_SUBSCRIBE_DURATION 180 /* 3 minutes */ +/* Note that PMC_SUBSCRIBE_DURATION has to be longer than + * PMC_UPDATE_INTERVAL otherwise subscription will time out before it is + * renewed. + */ struct clock { LIST_ENTRY(clock) list; clockid_t clkid; int sysoff_supported; int is_utc; + int state; + int new_state; struct servo *servo; enum servo_state servo_state; char *device; @@ -78,6 +86,7 @@ struct clock { struct port { LIST_ENTRY(port) list; unsigned int number; + int state; struct clock *clock; }; @@ -95,6 +104,7 @@ struct node { struct pmc *pmc; int pmc_ds_requested; uint64_t pmc_last_update; + int state_changed; LIST_HEAD(port_head, port) ports; LIST_HEAD(clock_head, clock) clocks; struct clock *master; @@ -533,6 +543,81 @@ static void *get_mgt_data(struct ptp_message *msg) return mgt->data; } +static int normalize_state(int state) +{ + if (state != PS_MASTER && state != PS_SLAVE && + state != PS_PRE_MASTER && state != PS_UNCALIBRATED) { + /* treat any other state as "not a master nor a slave" */ + state = PS_DISABLED; + } + return state; +} + +static int clock_compute_state(struct node *node, struct clock *clock) +{ + struct port *p; + int state = PS_DISABLED; + + LIST_FOREACH(p, &node->ports, list) { + if (p->clock != clock) + continue; + /* PS_SLAVE takes the highest precedence, PS_UNCALIBRATED +* after that, PS_MASTER is third, PS_PRE_MASTER fourth and +* all of that overrides PS_DISABLED, which corresponds +* nicely with the numerical values */ + if (p->state > state) + state = p->state; + } + return state; +} + +static int recv_subscribed(struct node *node, struct ptp_message *msg, + int excluded) +{ + int mgt_id, state; + struct portDS *pds; + struct port *port; + struct clock *clock; + + mgt_id = get_mgt_id(msg); + if (mgt_id == excluded) + return 0; + switch (mgt_id) { + case PORT_DATA_SET: + pds = get_mgt_data(msg); + port = port_get(node, pds->portIdentity.portNumber); + if (!port) { + pr_info("received data for unknown port %s", + pid2str(&pds->portIdentity)); + return 1; + } + state = normalize_state(pds->portState); + if (port->state != state) { + pr_info("port %s changed state", + pid2str(&pds->portIdentity)); + port->state = state; + clock = port->clock; + state = clock_compute_state(node, clock); + if (clock->state != state) { + clock->new_state = state; + node->state_changed = 1; + } + } + return 1; + } + return 0; +} + +static void send_subscription(struct node *node) +{ + struct subscribe_events_np sen; + + memset(&sen, 0, sizeof(sen)); + sen.duration = PMC_SUBSCRIBE_DURATION; + sen.bitmask[0] = 1 << NOTIFY_PORT_STATE; + pmc_send_set_action(node->pmc, SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen)); +} + static int init_pmc(struct node *node, int domain_number) { node->pmc = pmc_create(TRANS_UDS, "/var/run/phc2sys", 0, @@ -555,7 +640,7 @@ static int run_pmc(struct node *node, int timeout, int ds_id, while (1) { pollfd[0].fd = pmc_get_transport_fd(node->pmc); pollfd[0].events = POLLIN|POLLPRI; - if (!node->pmc_ds_requested) + if (!node->pmc_ds_requested && ds_id >=
Re: [Linuxptp-devel] linuxptp in kernel 2.6.30+?
On Tue, 3 Jun 2014 10:24:16 +0200, Richard Cochran wrote: > The reason I mentioned the RH and TI back ports was not to make > anybody look bad. Rather, I am trying to suggest that making a working > back port to 2.6.30 is not as easy as it sounds. This is something I can very much agree with :-) Jiri -- Jiri Benc -- Learn Graph Databases - Download FREE O'Reilly Book "Graph Databases" is the definitive new guide to graph databases and their applications. Written by three acclaimed leaders in the field, this first edition is now available. Download your free book today! http://p.sf.net/sfu/NeoTech ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] linuxptp in kernel 2.6.30+?
On Tue, 3 Jun 2014 09:33:28 +0200, Richard Cochran wrote: > On Mon, Jun 02, 2014 at 09:02:16PM +, Keller, Jacob E wrote: > > Redhat did a semi-decent job in their RHEL 6.4, and 6.5 kernels. I've > > tested ptp4l against them, and it mostly works. > > Wasn't someone asking about the RH backport on the linuxptp lists a > while back, with some unresolved problem? I would be very interested in such problems. RHEL 6.4 support was buggy (and it was not unexpected, we marked it as Tech Preview for a reason) but RHEL 6.5 should work. We even found and fixed several upstream problems while doing the backport. Feel free to send any problems in 6.5 you find my way. But this is off topic on this list... Jiri -- Jiri Benc -- Learn Graph Databases - Download FREE O'Reilly Book "Graph Databases" is the definitive new guide to graph databases and their applications. Written by three acclaimed leaders in the field, this first edition is now available. Download your free book today! http://p.sf.net/sfu/NeoTech ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH v2 04/14] phc2sys: store information about clocks being UTC or TAI
On Fri, 23 May 2014 10:32:28 +0200, Miroslav Lichvar wrote: > On Wed, May 14, 2014 at 03:39:40PM +0200, Jiri Benc wrote: > > For now, only CLOCK_REALTIME can be UTC. This may stay this way forever but > > now we have a clean separation between codepaths where CLOCK_REALTIME is > > required and codepaths any UTC clock should take. > > > > The main motiviation behind this change is removal of sync_offset_direction. > > It has to be computed on the fly based on the source and destination when we > > have multiple clocks supported and automatic following of ptp4l state > > changes implemented. > > I've noticed that the UTC-TAI offset is applied in the wrong > direction, I'm seeing 70s offset to UTC with this patch. Hmm, I see the error, 'offset' is slave - master, not master - slave. The strange thing is I remember testing this in various combinations of master/slave UTC/PTP time scale and offsets :-/ I'll fix this. Also, the second parameter to get_sync_offset is better named 'dst'. Thanks for the review, Jiri -- Jiri Benc -- Time is money. Stop wasting it! Get your web API in 5 minutes. www.restlet.com/download http://p.sf.net/sfu/restlet ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v2 11/14] phc2sys: autoconfiguration
Add automatic configuration option (-a). Signed-off-by: Jiri Benc --- phc2sys.c | 265 + 1 files changed, 250 insertions(+), 15 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index edb73be5080c..9a89667e1d47 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -110,9 +111,11 @@ struct node { struct clock *master; }; -static int update_sync_offset(struct node *node); +static int update_pmc(struct node *node, int subscribe); static int clock_handle_leap(struct node *node, struct clock *clock, int64_t offset, uint64_t ts, int do_leap); +static int run_pmc_get_utc_offset(struct node *node, int timeout); +static void run_pmc_events(struct node *node); static clockid_t clock_open(char *device) { @@ -267,6 +270,78 @@ static struct port *port_add(struct node *node, unsigned int number, return p; } +static void clock_reinit(struct clock *clock) +{ + servo_reset(clock->servo); + clock->servo_state = SERVO_UNLOCKED; + + if (clock->offset_stats) { + stats_reset(clock->offset_stats); + stats_reset(clock->freq_stats); + stats_reset(clock->delay_stats); + } +} + +static void reconfigure(struct node *node) +{ + struct clock *c, *rt, *src; + int src_cnt = 0, dst_cnt = 0; + + pr_info("reconfiguring after port state change"); + node->state_changed = 0; + + src = rt = NULL; + LIST_FOREACH(c, &node->clocks, list) { + if (c->clkid == CLOCK_REALTIME) { + rt = c; + continue; + } + + if (c->new_state == PS_MASTER) + clock_reinit(c); + + c->state = c->new_state; + c->new_state = 0; + + if (c->state == PS_SLAVE) { + src = c; + src_cnt++; + } else if (c->state == PS_UNCALIBRATED) { + src_cnt++; + } else if (c->state == PS_MASTER) { + pr_info("selecting %s for synchronization", c->device); + dst_cnt++; + } + } + if (src_cnt > 1) { + pr_info("multiple master clocks available, postponing sync..."); + node->master = NULL; + return; + } + if (src_cnt > 0 && !src) { + pr_info("master clock not ready, waiting..."); + node->master = NULL; + return; + } + if (!src_cnt && !dst_cnt) { + pr_info("no PHC ready, waiting..."); + node->master = NULL; + return; + } + if (!src_cnt) { + src = rt; + rt->state = PS_SLAVE; + } else { + if (rt->state != PS_MASTER) { + rt->state = PS_MASTER; + clock_reinit(rt); + } + pr_info("selecting %s for synchronization", rt->device); + } + node->master = src; + pr_info("selecting %s as the master clock", src->device); +} + static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, int64_t *offset, uint64_t *ts, int64_t *delay) { @@ -465,7 +540,7 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd) pps_offset = pps_ts - phc_ts; } - do_leap = update_sync_offset(node); + do_leap = update_pmc(node, 0); if (do_leap < 0) continue; update_clock(node, clock, pps_offset, pps_ts, -1, do_leap); @@ -474,13 +549,12 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd) return 0; } -static int do_loop(struct node *node) +static int do_loop(struct node *node, int subscriptions) { struct timespec interval; struct clock *clock; uint64_t ts; int64_t offset, delay; - int src_fd = CLOCKID_TO_FD(node->master->clkid); int do_leap; interval.tv_sec = node->phc_interval; @@ -488,18 +562,34 @@ static int do_loop(struct node *node) while (1) { clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL); - do_leap = update_sync_offset(node); + do_leap = update_pmc(node, subscriptions); if (do_leap < 0) continue; + if (subscriptions) { + run_pmc_events(node); + if (node->state_changed) { +
[Linuxptp-devel] [PATCH v2 14/14] phc2sys: man page update for -a and -r options
Signed-off-by: Jiri Benc --- phc2sys.8 | 115 ++--- 1 files changed, 79 insertions(+), 36 deletions(-) diff --git a/phc2sys.8 b/phc2sys.8 index fa3ae206f3df..37a39d0ba60f 100644 --- a/phc2sys.8 +++ b/phc2sys.8 @@ -1,12 +1,17 @@ .TH PHC2SYS 8 "November 2012" "linuxptp" .SH NAME -phc2sys \- synchronize two clocks +phc2sys \- synchronize two or more clocks .SH SYNOPSIS -.B phc2sys +.B phc2sys \-a [ -.B \-wmqvx +.B \-r ] [ +.B \-r +] [ options ] +.br +.B phc2sys +[ .BI \-d " pps-device" ] [ .BI \-s " device" @@ -15,45 +20,53 @@ phc2sys \- synchronize two clocks ] [ .BI \-O " offset" ] [ -.BI \-E " servo" -] [ -.BI \-P " kp" -] [ -.BI \-I " ki" -] [ -.BI \-S " step" -] [ -.BI \-F " step" -] [ -.BI \-R " update-rate" -] [ -.BI \-N " clock-readings" -] [ -.BI \-L " freq-limit" -] [ -.BI \-u " summary-updates" -] [ -.BI \-n " domain-number" -] [ -.BI \-l " print-level" -] +.BI \-w +] [ options ] .SH DESCRIPTION .B phc2sys -is a program which synchronizes two clocks in the system. Typically, it is used -to synchronize the system clock to a PTP hardware clock (PHC), which itself is -synchronized by the +is a program which synchronizes two or more clocks in the system. Typically, +it is used to synchronize the system clock to a PTP hardware clock (PHC), +which itself is synchronized by the .BR ptp4l (8) program. -Two synchronization modes are supported, one uses a pulse per second (PPS) +With the +.B \-a +option, the clocks to synchronize are fetched from the running +.B ptp4l +daemon and the direction of synchronization automatically follows changes of +the PTP port states. + +Manual configuration is also possible. When using manual configuration, two +synchronization modes are supported, one uses a pulse per second (PPS) signal provided by the source clock and the other mode reads time from the source clock directly. Some clocks can be used in both modes, the mode which -will synchronize the slave clock with better accuracy depends on hardware and -driver implementation. +will synchronize the slave clock with better accuracy depends on hardware +and driver implementation. .SH OPTIONS .TP +.BI \-a +Read the clocks to synchronize from running +.B ptp4l +and follow changes in the port states, adjusting the synchronization +direction automatically. The system clock (CLOCK_REALTIME) is not +synchronized, unless the +.B \-r +option is also specified. +.TP +.BI \-r +Only valid together with the +.B \-a +option. Instructs +.B phc2sys +to also synchronize the system clock (CLOCK_REALTIME). By default, the +system clock is not considered as a possible time source. If you want the +system clock to be eligible to become a time source, specify the +.B \-r +option twice. +.TP .BI \-d " pps-device" Specify the PPS device of the master clock (e.g. /dev/pps0). With this option the PPS synchronization mode is used instead of the direct mode. As the PPS @@ -68,7 +81,10 @@ option the PPS signal of the master clock is enabled automatically, otherwise it has to be enabled before .B phc2sys is started (e.g. by running \f(CWecho 1 > /sys/class/ptp/ptp0/pps_enable\fP). -This option can be used only with the system clock as the slave clock. +This option can be used only with the system clock as the slave clock. Not +compatible with the +.B \-a +option. .TP .BI \-s " device" Specify the master clock by device (e.g. /dev/ptp0) or interface (e.g. eth0) or @@ -76,7 +92,9 @@ by name (e.g. CLOCK_REALTIME for the system clock). When this option is used together with the .B \-d option, the master clock is used only to correct the offset by whole number of -seconds, which cannot be fixed with PPS alone. +seconds, which cannot be fixed with PPS alone. Not compatible with the +.B \-a +option. .TP .BI \-i " interface" Performs the exact same function as @@ -89,7 +107,10 @@ should no longer be used. .TP .BI \-c " device" Specify the slave clock by device (e.g. /dev/ptp1) or interface (e.g. eth1) or -by name. The default is CLOCK_REALTIME (the system clock). +by name. The default is CLOCK_REALTIME (the system clock). Not compatible +with the +.B \-a +option. .TP .BI \-E " servo" Specify which clock servo should be used. Valid values are pi for a PI @@ -128,7 +149,10 @@ minimize the error caused by random delays in scheduling and bus utilization. The default is 5. .TP .BI \-O " offset" -Specify the offset between the slave and master times in seconds. See +Specify the offset between the slave and master times in seconds. Not +compatible with the +.B \-a +option. See .SM .B TIME SCALE USAGE below. @@ -154,7 +178,9 @@ Wait until ptp4l is in a synchronized state. If the .B \-O option is not used, also keep the offse
[Linuxptp-devel] [PATCH v2 09/14] phc2sys: event subscription
Add support for subscribing to events (run_pmc_subscribe) and receiving and handling of received events (run_pmc_events). Add initial support for port status changes. Signed-off-by: Jiri Benc --- phc2sys.c | 116 +++- 1 files changed, 114 insertions(+), 2 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index ece4560e0c67..5b90bb2a5106 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -41,6 +41,7 @@ #include "ds.h" #include "fsm.h" #include "missing.h" +#include "notification.h" #include "phc.h" #include "pi.h" #include "pmc_common.h" @@ -59,12 +60,19 @@ #define PHC_PPS_OFFSET_LIMIT 1000 #define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC) +#define PMC_SUBSCRIBE_DURATION 180 /* 3 minutes */ +/* Note that PMC_SUBSCRIBE_DURATION has to be longer than + * PMC_UPDATE_INTERVAL otherwise subscription will time out before it is + * renewed. + */ struct clock { LIST_ENTRY(clock) list; clockid_t clkid; int sysoff_supported; int is_utc; + int state; + int new_state; struct servo *servo; enum servo_state servo_state; char *device; @@ -78,6 +86,7 @@ struct clock { struct port { LIST_ENTRY(port) list; unsigned int number; + int state; struct clock *clock; }; @@ -95,6 +104,7 @@ struct node { struct pmc *pmc; int pmc_ds_requested; uint64_t pmc_last_update; + int state_changed; LIST_HEAD(port_head, port) ports; LIST_HEAD(clock_head, clock) clocks; struct clock *master; @@ -533,6 +543,81 @@ static void *get_mgt_data(struct ptp_message *msg) return mgt->data; } +static int normalize_state(int state) +{ + if (state != PS_MASTER && state != PS_SLAVE && + state != PS_PRE_MASTER && state != PS_UNCALIBRATED) { + /* treat any other state as "not a master nor a slave" */ + state = PS_DISABLED; + } + return state; +} + +static int clock_compute_state(struct node *node, struct clock *clock) +{ + struct port *p; + int state = PS_DISABLED; + + LIST_FOREACH(p, &node->ports, list) { + if (p->clock != clock) + continue; + /* PS_SLAVE takes the highest precedence, PS_UNCALIBRATED +* after that, PS_MASTER is third, PS_PRE_MASTER fourth and +* all of that overrides PS_DISABLED, which corresponds +* nicely with the numerical values */ + if (p->state > state) + state = p->state; + } + return state; +} + +static int recv_subscribed(struct node *node, struct ptp_message *msg, + int excluded) +{ + int mgt_id, state; + struct portDS *pds; + struct port *port; + struct clock *clock; + + mgt_id = get_mgt_id(msg); + if (mgt_id == excluded) + return 0; + switch (mgt_id) { + case PORT_DATA_SET: + pds = get_mgt_data(msg); + port = port_get(node, pds->portIdentity.portNumber); + if (!port) { + pr_info("received data for unknown port %s", + pid2str(&pds->portIdentity)); + return 1; + } + state = normalize_state(pds->portState); + if (port->state != state) { + pr_info("port %s changed state", + pid2str(&pds->portIdentity)); + port->state = state; + clock = port->clock; + state = clock_compute_state(node, clock); + if (clock->state != state) { + clock->new_state = state; + node->state_changed = 1; + } + } + return 1; + } + return 0; +} + +static void send_subscription(struct node *node) +{ + struct subscribe_events_np sen; + + memset(&sen, 0, sizeof(sen)); + sen.duration = PMC_SUBSCRIBE_DURATION; + sen.bitmask[0] = 1 << NOTIFY_PORT_STATE; + pmc_send_set_action(node->pmc, SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen)); +} + static int init_pmc(struct node *node, int domain_number) { node->pmc = pmc_create(TRANS_UDS, "/var/run/phc2sys", 0, @@ -555,7 +640,7 @@ static int run_pmc(struct node *node, int timeout, int ds_id, while (1) { pollfd[0].fd = pmc_get_transport_fd(node->pmc); pollfd[0].events = POLLIN|POLLPRI; - if (!node->pmc_ds_requested) + if (!node->pmc_ds_requested && ds_id >=
[Linuxptp-devel] [PATCH v2 07/14] phc2sys: track ports
Add tracking of which ports have been added and to which clock they belong. Signed-off-by: Jiri Benc --- phc2sys.c | 51 +++ 1 files changed, 51 insertions(+), 0 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 62e9b8c19e17..ece4560e0c67 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -75,6 +75,12 @@ struct clock { struct clockcheck *sanity_check; }; +struct port { + LIST_ENTRY(port) list; + unsigned int number; + struct clock *clock; +}; + struct node { unsigned int stats_max_count; int sanity_freq_limit; @@ -89,6 +95,7 @@ struct node { struct pmc *pmc; int pmc_ds_requested; uint64_t pmc_last_update; + LIST_HEAD(port_head, port) ports; LIST_HEAD(clock_head, clock) clocks; struct clock *master; }; @@ -206,6 +213,50 @@ static struct clock *clock_add(struct node *node, char *device) return c; } +static struct port *port_get(struct node *node, unsigned int number) +{ + struct port *p; + + LIST_FOREACH(p, &node->ports, list) { + if (p->number == number) + return p; + } + return NULL; +} + +static struct port *port_add(struct node *node, unsigned int number, +char *device) +{ + struct port *p; + struct clock *c = NULL, *tmp; + + p = port_get(node, number); + if (p) + return p; + /* port is a new one, look whether we have the device already on +* a different port */ + LIST_FOREACH(tmp, &node->clocks, list) { + if (!strcmp(tmp->device, device)) { + c = tmp; + break; + } + } + if (!c) { + c = clock_add(node, device); + if (!c) + return NULL; + } + p = malloc(sizeof(*p)); + if (!p) { + pr_err("failed to allocate memory for a port"); + return NULL; + } + p->number = number; + p->clock = c; + LIST_INSERT_HEAD(&node->ports, p, list); + return p; +} + static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, int64_t *offset, uint64_t *ts, int64_t *delay) { -- 1.7.6.5 -- "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE Instantly run your Selenium tests across 300+ browser/OS combos. Get unparalleled scalability from the best Selenium testing platform available Simple to use. Nothing to install. Get started now for free." http://p.sf.net/sfu/SauceLabs ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v2 08/14] pmc_common: easy way to set port and broadcast target
Implement pmc_target_port to set a port number, leaving clock identity unchanged, and pmc_target_all to set clock identity and port number to all 1's. Signed-off-by: Jiri Benc --- pmc_common.c | 12 +++- pmc_common.h |2 ++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/pmc_common.c b/pmc_common.c index 2c75074c8fb7..41385da45209 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -78,7 +78,7 @@ struct pmc *pmc_create(enum transport_type transport_type, const char *iface_nam goto failed; } pmc->port_identity.portNumber = 1; - memset(&pmc->target, 0xff, sizeof(pmc->target)); + pmc_target_all(pmc); pmc->boundary_hops = boundary_hops; pmc->domain_number = domain_number; @@ -325,3 +325,13 @@ int pmc_target(struct pmc *pmc, struct PortIdentity *pid) pmc->target = *pid; return 0; } + +void pmc_target_port(struct pmc *pmc, UInteger16 portNumber) +{ + pmc->target.portNumber = portNumber; +} + +void pmc_target_all(struct pmc *pmc) +{ + memset(&pmc->target, 0xff, sizeof(pmc->target)); +} diff --git a/pmc_common.h b/pmc_common.h index 9fcb51da3fd4..9adb9d1dd98b 100644 --- a/pmc_common.h +++ b/pmc_common.h @@ -41,5 +41,7 @@ int pmc_send_set_action(struct pmc *pmc, int id, void *data, int datasize); struct ptp_message *pmc_recv(struct pmc *pmc); int pmc_target(struct pmc *pmc, struct PortIdentity *pid); +void pmc_target_port(struct pmc *pmc, UInteger16 portNumber); +void pmc_target_all(struct pmc *pmc); #endif -- 1.7.6.5 -- "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE Instantly run your Selenium tests across 300+ browser/OS combos. Get unparalleled scalability from the best Selenium testing platform available Simple to use. Nothing to install. Get started now for free." http://p.sf.net/sfu/SauceLabs ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v2 05/14] phc2sys: rearrange declarations
This just moves code around to have related functions together and forward declaration at the beginning of the file. No code changes. Signed-off-by: Jiri Benc --- phc2sys.c | 208 ++--- 1 files changed, 103 insertions(+), 105 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 6c86b4d9f028..34f5f94ccb91 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -60,7 +60,41 @@ #define PHC_PPS_OFFSET_LIMIT 1000 #define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC) -struct clock; +struct clock { + LIST_ENTRY(clock) list; + clockid_t clkid; + int sysoff_supported; + int is_utc; + struct servo *servo; + enum servo_state servo_state; + const char *source_label; + struct stats *offset_stats; + struct stats *freq_stats; + struct stats *delay_stats; + struct clockcheck *sanity_check; +}; + +struct node { + unsigned int stats_max_count; + int sanity_freq_limit; + enum servo_type servo_type; + int phc_readings; + double phc_interval; + int sync_offset; + int forced_sync_offset; + int leap; + int leap_set; + int kernel_leap; + struct pmc *pmc; + int pmc_ds_requested; + uint64_t pmc_last_update; + LIST_HEAD(clock_head, clock) clocks; + struct clock *master; +}; + +static int update_sync_offset(struct node *node); +static int clock_handle_leap(struct node *node, struct clock *clock, +int64_t offset, uint64_t ts, int do_leap); static clockid_t clock_open(char *device) { @@ -95,6 +129,74 @@ static clockid_t clock_open(char *device) return clkid; } +static int clock_add(struct node *node, clockid_t clkid) +{ + struct clock *c; + int max_ppb; + double ppb; + + c = calloc(1, sizeof(*c)); + if (!c) { + pr_err("failed to allocate memory for a clock"); + return -1; + } + c->clkid = clkid; + c->servo_state = SERVO_UNLOCKED; + + if (c->clkid == CLOCK_REALTIME) { + c->source_label = "sys"; + c->is_utc = 1; + } else { + c->source_label = "phc"; + } + + if (node->stats_max_count > 0) { + c->offset_stats = stats_create(); + c->freq_stats = stats_create(); + c->delay_stats = stats_create(); + if (!c->offset_stats || + !c->freq_stats || + !c->delay_stats) { + pr_err("failed to create stats"); + return -1; + } + } + if (node->sanity_freq_limit) { + c->sanity_check = clockcheck_create(node->sanity_freq_limit); + if (!c->sanity_check) { + pr_err("failed to create clock check"); + return -1; + } + } + + clockadj_init(c->clkid); + ppb = clockadj_get_freq(c->clkid); + /* The reading may silently fail and return 0, reset the frequency to + make sure ppb is the actual frequency of the clock. */ + clockadj_set_freq(c->clkid, ppb); + if (c->clkid == CLOCK_REALTIME) { + sysclk_set_leap(0); + max_ppb = sysclk_max_freq(); + } else { + max_ppb = phc_max_adj(c->clkid); + if (!max_ppb) { + pr_err("clock is not adjustable"); + return -1; + } + } + + c->servo = servo_create(node->servo_type, -ppb, max_ppb, 0); + servo_sync_interval(c->servo, node->phc_interval); + + if (clkid != CLOCK_REALTIME) + c->sysoff_supported = (SYSOFF_SUPPORTED == + sysoff_probe(CLOCKID_TO_FD(clkid), + node->phc_readings)); + + LIST_INSERT_HEAD(&node->clocks, c, list); + return 0; +} + static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, int64_t *offset, uint64_t *ts, int64_t *delay) { @@ -126,42 +228,6 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, return 1; } -struct clock { - LIST_ENTRY(clock) list; - clockid_t clkid; - int sysoff_supported; - int is_utc; - struct servo *servo; - enum servo_state servo_state; - const char *source_label; - struct stats *offset_stats; - struct stats *freq_stats; - struct stats *delay_stats; - struct clockcheck *sanity_check; -}; - -struct node { - unsigned int stats_max_count; - int sanity_freq_limit; - enum servo_type servo_type; - int phc_readings; - double phc_interval; - int sync_offs
[Linuxptp-devel] [PATCH v2 04/14] phc2sys: store information about clocks being UTC or TAI
For now, only CLOCK_REALTIME can be UTC. This may stay this way forever but now we have a clean separation between codepaths where CLOCK_REALTIME is required and codepaths any UTC clock should take. The main motiviation behind this change is removal of sync_offset_direction. It has to be computed on the fly based on the source and destination when we have multiple clocks supported and automatic following of ptp4l state changes implemented. Signed-off-by: Jiri Benc --- phc2sys.c | 60 +--- 1 files changed, 29 insertions(+), 31 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 825d7328af15..6c86b4d9f028 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -130,6 +130,7 @@ struct clock { LIST_ENTRY(clock) list; clockid_t clkid; int sysoff_supported; + int is_utc; struct servo *servo; enum servo_state servo_state; const char *source_label; @@ -146,7 +147,7 @@ struct node { int phc_readings; double phc_interval; int sync_offset; - int sync_offset_direction; + int forced_sync_offset; int leap; int leap_set; int kernel_leap; @@ -161,6 +162,15 @@ static int update_sync_offset(struct node *node); static int clock_handle_leap(struct node *node, struct clock *clock, int64_t offset, uint64_t ts, int do_leap); +static int64_t get_sync_offset(struct node *node, struct clock *src) +{ + int direction = node->forced_sync_offset; + + if (!direction) + direction = node->master->is_utc - src->is_utc; + return (int64_t)node->sync_offset * NS_PER_SEC * direction; +} + static void update_clock_stats(struct clock *clock, unsigned int max_count, int64_t offset, double freq, int64_t delay) { @@ -206,9 +216,7 @@ static void update_clock(struct node *node, struct clock *clock, if (clock_handle_leap(node, clock, offset, ts, do_leap)) return; - if (node->sync_offset_direction) - offset += node->sync_offset * NS_PER_SEC * - node->sync_offset_direction; + offset += get_sync_offset(node, clock); if (clock->sanity_check && clockcheck_sample(clock->sanity_check, ts)) servo_reset(clock->servo); @@ -290,7 +298,7 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd) if (src == CLOCK_INVALID) { /* The sync offset can't be applied with PPS alone. */ - node->sync_offset_direction = 0; + node->sync_offset = 0; } else { enable_pps_output(node->master->clkid); } @@ -558,15 +566,14 @@ static int clock_handle_leap(struct node *node, struct clock *clock, if (!node->leap && !do_leap) return 0; - if (clock->clkid != CLOCK_REALTIME && - node->master->clkid != CLOCK_REALTIME) + if (clock->is_utc == node->master->is_utc) return 0; /* If the system clock is the master clock, get a time stamp from it, as it is the clock which will include the leap second. */ - if (node->master->clkid == CLOCK_REALTIME) { + if (node->master->is_utc) { struct timespec tp; - if (clock_gettime(CLOCK_REALTIME, &tp)) { + if (clock_gettime(node->master->clkid, &tp)) { pr_err("failed to read clock: %m"); return -1; } @@ -575,11 +582,8 @@ static int clock_handle_leap(struct node *node, struct clock *clock, /* If the clock will be stepped, the time stamp has to be the target time. Ignore possible 1 second error in UTC offset. */ - if (clock->clkid == CLOCK_REALTIME && - clock->servo_state == SERVO_UNLOCKED) { - ts -= offset + node->sync_offset * NS_PER_SEC * - node->sync_offset_direction; - } + if (clock->is_utc && clock->servo_state == SERVO_UNLOCKED) + ts -= get_sync_offset(node, clock); /* Suspend clock updates in the last second before midnight. */ if (is_utc_ambiguous(ts)) { @@ -610,10 +614,12 @@ static int clock_add(struct node *node, clockid_t clkid) c->clkid = clkid; c->servo_state = SERVO_UNLOCKED; - if (c->clkid == CLOCK_REALTIME) + if (c->clkid == CLOCK_REALTIME) { c->source_label = "sys"; - else + c->is_utc = 1; + } else { c->source_label = "phc"; + } if (node->stats_max_count > 0) { c->offset_stats = stats_create(); @@ -698,7 +704,7 @@ int main(int argc, cha
[Linuxptp-devel] [PATCH v2 06/14] phc2sys: open devices in clock_add
Do not call clock_open to open a clock device but let clock_add do that and return the newly created struct. Also, store the device (interface) name in struct clock. Signed-off-by: Jiri Benc --- phc2sys.c | 81 ++-- 1 files changed, 46 insertions(+), 35 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 34f5f94ccb91..62e9b8c19e17 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -67,6 +67,7 @@ struct clock { int is_utc; struct servo *servo; enum servo_state servo_state; + char *device; const char *source_label; struct stats *offset_stats; struct stats *freq_stats; @@ -129,19 +130,27 @@ static clockid_t clock_open(char *device) return clkid; } -static int clock_add(struct node *node, clockid_t clkid) +static struct clock *clock_add(struct node *node, char *device) { struct clock *c; + clockid_t clkid = CLOCK_INVALID; int max_ppb; double ppb; + if (device) { + clkid = clock_open(device); + if (clkid == CLOCK_INVALID) + return NULL; + } + c = calloc(1, sizeof(*c)); if (!c) { pr_err("failed to allocate memory for a clock"); - return -1; + return NULL; } c->clkid = clkid; c->servo_state = SERVO_UNLOCKED; + c->device = strdup(device); if (c->clkid == CLOCK_REALTIME) { c->source_label = "sys"; @@ -158,14 +167,14 @@ static int clock_add(struct node *node, clockid_t clkid) !c->freq_stats || !c->delay_stats) { pr_err("failed to create stats"); - return -1; + return NULL; } } if (node->sanity_freq_limit) { c->sanity_check = clockcheck_create(node->sanity_freq_limit); if (!c->sanity_check) { pr_err("failed to create clock check"); - return -1; + return NULL; } } @@ -181,7 +190,7 @@ static int clock_add(struct node *node, clockid_t clkid) max_ppb = phc_max_adj(c->clkid); if (!max_ppb) { pr_err("clock is not adjustable"); - return -1; + return NULL; } } @@ -194,7 +203,7 @@ static int clock_add(struct node *node, clockid_t clkid) node->phc_readings)); LIST_INSERT_HEAD(&node->clocks, c, list); - return 0; + return c; } static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, @@ -699,8 +708,8 @@ static void usage(char *progname) int main(int argc, char *argv[]) { char *progname; - clockid_t src = CLOCK_INVALID; - clockid_t dst = CLOCK_REALTIME; + char *src_name = NULL, *dst_name = NULL; + struct clock *src, *dst; int c, domain_number = 0, pps_fd = -1; int r, wait_sync = 0; int print_level = LOG_INFO, use_syslog = 1, verbose = 0; @@ -723,7 +732,7 @@ int main(int argc, char *argv[]) "c:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xl:mqvh"))) { switch (c) { case 'c': - dst = clock_open(optarg); + dst_name = strdup(optarg); break; case 'd': pps_fd = open(optarg, O_RDONLY); @@ -737,7 +746,7 @@ int main(int argc, char *argv[]) fprintf(stderr, "'-i' has been deprecated. please use '-s' instead.\n"); case 's': - src = clock_open(optarg); + src_name = strdup(optarg); break; case 'E': if (!strcasecmp(optarg, "pi")) { @@ -826,38 +835,46 @@ int main(int argc, char *argv[]) } } - if (pps_fd < 0 && src == CLOCK_INVALID) { + if (pps_fd < 0 && !src_name) { fprintf(stderr, "valid source clock must be selected.\n"); goto bad_usage; } - if (dst == CLOCK_INVALID) { + if (!wait_sync && !node.forced_sync_offset) { fprintf(stderr, - "valid destination clock must be selected.\n"); + "time offset must be specified using -w or -O\n"); goto bad_usage; } - if (pps_fd >= 0 && dst != CLOCK_REALTIME) {
[Linuxptp-devel] [PATCH v2 13/14] phc2sys: check clockIdentity
Make sure that we handle only one PTP clock (node). This is for an extra safety. Signed-off-by: Jiri Benc --- phc2sys.c | 44 ++-- 1 files changed, 42 insertions(+), 2 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 52417268305c..f630ab05c9ed 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -107,6 +107,8 @@ struct node { int pmc_ds_requested; uint64_t pmc_last_update; int state_changed; + int clock_identity_set; + struct ClockIdentity clock_identity; LIST_HEAD(port_head, port) ports; LIST_HEAD(clock_head, clock) clocks; struct clock *master; @@ -612,6 +614,15 @@ static int do_loop(struct node *node, int subscriptions) return 0; /* unreachable */ } +static int check_clock_identity(struct node *node, struct ptp_message *msg) +{ + if (!node->clock_identity_set) + return 1; + return !memcmp(&node->clock_identity, + &msg->header.sourcePortIdentity.clockIdentity, + sizeof(struct ClockIdentity)); +} + static int is_msg_mgt(struct ptp_message *msg) { struct TLV *tlv; @@ -789,6 +800,12 @@ static int run_pmc(struct node *node, int timeout, int ds_id, if (!*msg) continue; + if (!check_clock_identity(node, *msg)) { + msg_put(*msg); + *msg = NULL; + continue; + } + res = is_msg_mgt(*msg); if (res < 0 && get_mgt_err_id(*msg) == ds_id) { node->pmc_ds_requested = 0; @@ -927,6 +944,24 @@ out: return res; } +static int run_pmc_clock_identity(struct node *node, int timeout) +{ + struct ptp_message *msg; + struct defaultDS *dds; + int res; + + res = run_pmc(node, timeout, DEFAULT_DATA_SET, &msg); + if (res <= 0) + return res; + + dds = (struct defaultDS *)get_mgt_data(msg); + memcpy(&node->clock_identity, &dds->clockIdentity, + sizeof(struct ClockIdentity)); + node->clock_identity_set = 1; + msg_put(msg); + return 1; +} + static void close_pmc(struct node *node) { pmc_destroy(node->pmc); @@ -943,7 +978,7 @@ static int auto_init_ports(struct node *node, int add_rt) char iface[IFNAMSIZ]; while (1) { - res = run_pmc_get_number_ports(node, 1000); + res = run_pmc_clock_identity(node, 1000); if (res < 0) return -1; if (res > 0) @@ -951,7 +986,12 @@ static int auto_init_ports(struct node *node, int add_rt) /* res == 0, timeout */ pr_notice("Waiting for ptp4l..."); } - number_ports = res; + + number_ports = run_pmc_get_number_ports(node, 1000); + if (number_ports <= 0) { + pr_err("failed to get number of ports"); + return -1; + } res = run_pmc_subscribe(node, 1000); if (res <= 0) { -- 1.7.6.5 -- "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE Instantly run your Selenium tests across 300+ browser/OS combos. Get unparalleled scalability from the best Selenium testing platform available Simple to use. Nothing to install. Get started now for free." http://p.sf.net/sfu/SauceLabs ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v2 12/14] phc2sys: autoconfigure realtime clock on demand only
By default, do not synchronize CLOCK_REALTIME. To do it, -r option is needed. That will only consider CLOCK_REALTIME as the destination. To consider it also as a possible time source, use -rr. Signed-off-by: Jiri Benc --- phc2sys.c | 31 --- 1 files changed, 24 insertions(+), 7 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 9a89667e1d47..52417268305c 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -72,6 +72,7 @@ struct clock { clockid_t clkid; int sysoff_supported; int is_utc; + int dest_only; int state; int new_state; struct servo *servo; @@ -328,10 +329,16 @@ static void reconfigure(struct node *node) node->master = NULL; return; } + if ((!src_cnt && (!rt || rt->dest_only)) || + (!dst_cnt && !rt)) { + pr_info("nothing to synchronize"); + node->master = NULL; + return; + } if (!src_cnt) { src = rt; rt->state = PS_SLAVE; - } else { + } else if (rt) { if (rt->state != PS_MASTER) { rt->state = PS_MASTER; clock_reinit(rt); @@ -926,7 +933,7 @@ static void close_pmc(struct node *node) node->pmc = NULL; } -static int auto_init_ports(struct node *node) +static int auto_init_ports(struct node *node, int add_rt) { struct port *port; struct clock *clock; @@ -981,8 +988,13 @@ static int auto_init_ports(struct node *node) } node->state_changed = 1; - if (!clock_add(node, "CLOCK_REALTIME")) - return -1; + if (add_rt) { + clock = clock_add(node, "CLOCK_REALTIME"); + if (!clock) + return -1; + if (add_rt == 1) + clock->dest_only = 1; + } /* get initial offset */ if (run_pmc_get_utc_offset(node, 1000) <= 0) { @@ -1077,6 +1089,8 @@ static void usage(char *progname) "\n" " automatic configuration:\n" " -a turn on autoconfiguration\n" + " -r synchronize system (realtime) clock\n" + "repeat -r to consider it also as a time source\n" " manual configuration:\n" " -c [dev|name] slave clock (CLOCK_REALTIME)\n" " -d [dev] master PPS device\n" @@ -1109,7 +1123,7 @@ int main(int argc, char *argv[]) char *progname; char *src_name = NULL, *dst_name = NULL; struct clock *src, *dst; - int autocfg = 0; + int autocfg = 0, rt = 0; int c, domain_number = 0, pps_fd = -1; int r, wait_sync = 0; int print_level = LOG_INFO, use_syslog = 1, verbose = 0; @@ -1129,11 +1143,14 @@ int main(int argc, char *argv[]) progname = strrchr(argv[0], '/'); progname = progname ? 1+progname : argv[0]; while (EOF != (c = getopt(argc, argv, - "ac:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xl:mqvh"))) { + "arc:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xl:mqvh"))) { switch (c) { case 'a': autocfg = 1; break; + case 'r': + rt++; + break; case 'c': dst_name = strdup(optarg); break; @@ -1263,7 +1280,7 @@ int main(int argc, char *argv[]) if (autocfg) { if (init_pmc(&node, domain_number)) return -1; - if (auto_init_ports(&node) < 0) + if (auto_init_ports(&node, rt) < 0) return -1; return do_loop(&node, 1); } -- 1.7.6.5 -- "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE Instantly run your Selenium tests across 300+ browser/OS combos. Get unparalleled scalability from the best Selenium testing platform available Simple to use. Nothing to install. Get started now for free." http://p.sf.net/sfu/SauceLabs ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v2 03/14] phc2sys: split clock and node
Split members that apply to all synchronized clocks and members that apply to an individual clock. Keep all clocks in a list, with a pointer to the source clock. This will allow to support multiple clocks synchronization. Signed-off-by: Jiri Benc --- phc2sys.c | 397 +--- 1 files changed, 218 insertions(+), 179 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 19dce45964eb..825d7328af15 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -60,9 +61,6 @@ #define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC) struct clock; -static int update_sync_offset(struct clock *clock); -static int clock_handle_leap(struct clock *clock, clockid_t src, -int64_t offset, uint64_t ts, int do_leap); static clockid_t clock_open(char *device) { @@ -129,14 +127,24 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, } struct clock { + LIST_ENTRY(clock) list; clockid_t clkid; + int sysoff_supported; struct servo *servo; enum servo_state servo_state; const char *source_label; struct stats *offset_stats; struct stats *freq_stats; struct stats *delay_stats; + struct clockcheck *sanity_check; +}; + +struct node { unsigned int stats_max_count; + int sanity_freq_limit; + enum servo_type servo_type; + int phc_readings; + double phc_interval; int sync_offset; int sync_offset_direction; int leap; @@ -145,10 +153,15 @@ struct clock { struct pmc *pmc; int pmc_ds_requested; uint64_t pmc_last_update; - struct clockcheck *sanity_check; + LIST_HEAD(clock_head, clock) clocks; + struct clock *master; }; -static void update_clock_stats(struct clock *clock, +static int update_sync_offset(struct node *node); +static int clock_handle_leap(struct node *node, struct clock *clock, +int64_t offset, uint64_t ts, int do_leap); + +static void update_clock_stats(struct clock *clock, unsigned int max_count, int64_t offset, double freq, int64_t delay) { struct stats_result offset_stats, freq_stats, delay_stats; @@ -158,7 +171,7 @@ static void update_clock_stats(struct clock *clock, if (delay >= 0) stats_add_value(clock->delay_stats, delay); - if (stats_get_num_values(clock->offset_stats) < clock->stats_max_count) + if (stats_get_num_values(clock->offset_stats) < max_count) return; stats_get_result(clock->offset_stats, &offset_stats); @@ -183,19 +196,19 @@ static void update_clock_stats(struct clock *clock, stats_reset(clock->delay_stats); } -static void update_clock(struct clock *clock, clockid_t src, +static void update_clock(struct node *node, struct clock *clock, int64_t offset, uint64_t ts, int64_t delay, int do_leap) { enum servo_state state; double ppb; - if (clock_handle_leap(clock, src, offset, ts, do_leap)) + if (clock_handle_leap(node, clock, offset, ts, do_leap)) return; - if (clock->sync_offset_direction) - offset += clock->sync_offset * NS_PER_SEC * - clock->sync_offset_direction; + if (node->sync_offset_direction) + offset += node->sync_offset * NS_PER_SEC * + node->sync_offset_direction; if (clock->sanity_check && clockcheck_sample(clock->sanity_check, ts)) servo_reset(clock->servo); @@ -221,15 +234,15 @@ static void update_clock(struct clock *clock, clockid_t src, } if (clock->offset_stats) { - update_clock_stats(clock, offset, ppb, delay); + update_clock_stats(clock, node->stats_max_count, offset, ppb, delay); } else { if (delay >= 0) { pr_info("%s offset %9" PRId64 " s%d freq %+7.0f " "delay %6" PRId64, - clock->source_label, offset, state, ppb, delay); + node->master->source_label, offset, state, ppb, delay); } else { pr_info("%s offset %9" PRId64 " s%d freq %+7.0f", - clock->source_label, offset, state, ppb); + node->master->source_label, offset, state, ppb); } } } @@ -266,20 +279,20 @@ static int read_pps(int fd, int64_t *offset, uint64_t *ts) return 1; } -static int do_pps_loop(struct clock *clock, int fd, - clockid_t src, int n_readings)
[Linuxptp-devel] [PATCH v2 10/14] phc2sys: propagate received errors
Recognize errors returned in MANAGEMENT_ERROR_STATUS TLV and return a distinct value from run_pmc in case such error is received. Signed-off-by: Jiri Benc --- phc2sys.c | 34 +++--- 1 files changed, 27 insertions(+), 7 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 5b90bb2a5106..edb73be5080c 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -526,9 +526,11 @@ static int is_msg_mgt(struct ptp_message *msg) if (msg->tlv_count != 1) return 0; tlv = (struct TLV *) msg->management.suffix; - if (tlv->type != TLV_MANAGEMENT) - return 0; - return 1; + if (tlv->type == TLV_MANAGEMENT) + return 1; + if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS) + return -1; + return 0; } static int get_mgt_id(struct ptp_message *msg) @@ -543,6 +545,14 @@ static void *get_mgt_data(struct ptp_message *msg) return mgt->data; } +static int get_mgt_err_id(struct ptp_message *msg) +{ + struct management_error_status *mgt; + + mgt = (struct management_error_status *)msg->management.suffix; + return mgt->id; +} + static int normalize_state(int state) { if (state != PS_MASTER && state != PS_SLAVE && @@ -630,12 +640,18 @@ static int init_pmc(struct node *node, int domain_number) return 0; } +/* Return values: + * 1: success + * 0: timeout + * -1: error reported by the other side + * -2: local error, fatal + */ static int run_pmc(struct node *node, int timeout, int ds_id, struct ptp_message **msg) { #define N_FD 1 struct pollfd pollfd[N_FD]; - int cnt; + int cnt, res; while (1) { pollfd[0].fd = pmc_get_transport_fd(node->pmc); @@ -646,7 +662,7 @@ static int run_pmc(struct node *node, int timeout, int ds_id, cnt = poll(pollfd, N_FD, timeout); if (cnt < 0) { pr_err("poll failed"); - return -1; + return -2; } if (!cnt) { /* Request the data set again in the next run. */ @@ -676,8 +692,12 @@ static int run_pmc(struct node *node, int timeout, int ds_id, if (!*msg) continue; - if (!is_msg_mgt(*msg) || - recv_subscribed(node, *msg, ds_id) || + res = is_msg_mgt(*msg); + if (res < 0 && get_mgt_err_id(*msg) == ds_id) { + node->pmc_ds_requested = 0; + return -1; + } + if (res <= 0 || recv_subscribed(node, *msg, ds_id) || get_mgt_id(*msg) != ds_id) { msg_put(*msg); *msg = NULL; -- 1.7.6.5 -- "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE Instantly run your Selenium tests across 300+ browser/OS combos. Get unparalleled scalability from the best Selenium testing platform available Simple to use. Nothing to install. Get started now for free." http://p.sf.net/sfu/SauceLabs ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v2 01/14] phc2sys: generalize run_pmc
Make run_pmc usable for any kind of management message. Create wrappers for waiting for ptp4l and for getting UTC offset. Signed-off-by: Jiri Benc --- phc2sys.c | 131 +++-- 1 files changed, 66 insertions(+), 65 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 5ecb602120c3..0581eb5bcb24 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -141,7 +141,6 @@ struct clock { int leap_set; int kernel_leap; struct pmc *pmc; - int pmc_ds_idx; int pmc_ds_requested; uint64_t pmc_last_update; struct clockcheck *sanity_check; @@ -390,31 +389,14 @@ static int init_pmc(struct clock *clock, int domain_number) return 0; } -static int run_pmc(struct clock *clock, int timeout, - int wait_sync, int get_utc_offset) +static int run_pmc(struct clock *clock, int timeout, int ds_id, + struct ptp_message **msg) { - struct ptp_message *msg; - struct timePropertiesDS *tds; - void *data; #define N_FD 1 struct pollfd pollfd[N_FD]; - int cnt, ds_done; -#define N_ID 2 - int ds_ids[N_ID] = { - PORT_DATA_SET, - TIME_PROPERTIES_DATA_SET - }; - - while (clock->pmc_ds_idx < N_ID) { - /* Check if the data set is really needed. */ - if ((ds_ids[clock->pmc_ds_idx] == PORT_DATA_SET && -!wait_sync) || - (ds_ids[clock->pmc_ds_idx] == TIME_PROPERTIES_DATA_SET && -!get_utc_offset)) { - clock->pmc_ds_idx++; - continue; - } + int cnt; + while (1) { pollfd[0].fd = pmc_get_transport_fd(clock->pmc); pollfd[0].events = POLLIN|POLLPRI; if (!clock->pmc_ds_requested) @@ -434,62 +416,76 @@ static int run_pmc(struct clock *clock, int timeout, /* Send a new request if there are no pending messages. */ if ((pollfd[0].revents & POLLOUT) && !(pollfd[0].revents & (POLLIN|POLLPRI))) { - pmc_send_get_action(clock->pmc, - ds_ids[clock->pmc_ds_idx]); + pmc_send_get_action(clock->pmc, ds_id); clock->pmc_ds_requested = 1; } if (!(pollfd[0].revents & (POLLIN|POLLPRI))) continue; - msg = pmc_recv(clock->pmc); + *msg = pmc_recv(clock->pmc); - if (!msg) + if (!*msg) continue; - if (!is_msg_mgt(msg) || - get_mgt_id(msg) != ds_ids[clock->pmc_ds_idx]) { - msg_put(msg); + if (!is_msg_mgt(*msg) || + get_mgt_id(*msg) != ds_id) { + msg_put(*msg); + *msg = NULL; continue; } + clock->pmc_ds_requested = 0; + return 1; + } +} - data = get_mgt_data(msg); - ds_done = 0; - - switch (get_mgt_id(msg)) { - case PORT_DATA_SET: - switch (((struct portDS *)data)->portState) { - case PS_MASTER: - case PS_SLAVE: - ds_done = 1; - break; - } +static int run_pmc_wait_sync(struct clock *clock, int timeout) +{ + struct ptp_message *msg; + int res; + void *data; + Enumeration8 portState; - break; - case TIME_PROPERTIES_DATA_SET: - tds = (struct timePropertiesDS *)data; - if (tds->flags & PTP_TIMESCALE) { - clock->sync_offset = tds->currentUtcOffset; - if (tds->flags & LEAP_61) - clock->leap = 1; - else if (tds->flags & LEAP_59) - clock->leap = -1; - else - clock->leap = 0; - } - ds_done = 1; - break; - } + while (1) { + res = run_pmc(clock, timeout, PORT_DATA_SET, &msg); + if (res <= 0) + return res; - if (ds_done) { - /* Proceed with the next data set. */ - clock->pmc_ds_idx++; - clock->pmc_ds_requested = 0; - } + data = get_mgt_data(msg); + port
[Linuxptp-devel] [PATCH v2 00/14] automatic phc2sys configuration, phc2sys part
Changes in v2: - added PMC_SUBSCRIBE_DURATION constant - fixed wrong invocation of update_pmc This is the phc2sys part of the autoconfig patchset. It uses the event subscription mechanism implemented in ptp4l. The patchset is prepared to handle the "emulated boundary clock" scenario, i.e. ptp4l working over multiple PHC's. I have old patches to do that (the dynamic port allocation patchset + patchset to support multiple PHC's) which I'll rebase on top of this and post after the patchset is accepted. Jiri Benc (14): phc2sys: generalize run_pmc phc2sys: split update_sync_offset phc2sys: split clock and node phc2sys: store information about clocks being UTC or TAI phc2sys: rearrange declarations phc2sys: open devices in clock_add phc2sys: track ports pmc_common: easy way to set port and broadcast target phc2sys: event subscription phc2sys: propagate received errors phc2sys: autoconfiguration phc2sys: autoconfigure realtime clock on demand only phc2sys: check clockIdentity phc2sys: man page update for -a and -r options phc2sys.8| 115 +-- phc2sys.c| 1081 -- pmc_common.c | 12 +- pmc_common.h |2 + 4 files changed, 913 insertions(+), 297 deletions(-) -- 1.7.6.5 -- "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE Instantly run your Selenium tests across 300+ browser/OS combos. Get unparalleled scalability from the best Selenium testing platform available Simple to use. Nothing to install. Get started now for free." http://p.sf.net/sfu/SauceLabs ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH v2 02/14] phc2sys: split update_sync_offset
Split the generic (global) part of update_sync_offset and the part that affects individual clocks. This is in preparation for phc2sys handling synchronization of more clocks. Signed-off-by: Jiri Benc --- phc2sys.c | 71 +++- 1 files changed, 55 insertions(+), 16 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 0581eb5bcb24..19dce45964eb 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -60,7 +60,9 @@ #define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC) struct clock; -static int update_sync_offset(struct clock *clock, int64_t offset, uint64_t ts); +static int update_sync_offset(struct clock *clock); +static int clock_handle_leap(struct clock *clock, clockid_t src, +int64_t offset, uint64_t ts, int do_leap); static clockid_t clock_open(char *device) { @@ -181,13 +183,14 @@ static void update_clock_stats(struct clock *clock, stats_reset(clock->delay_stats); } -static void update_clock(struct clock *clock, -int64_t offset, uint64_t ts, int64_t delay) +static void update_clock(struct clock *clock, clockid_t src, +int64_t offset, uint64_t ts, int64_t delay, +int do_leap) { enum servo_state state; double ppb; - if (update_sync_offset(clock, offset, ts)) + if (clock_handle_leap(clock, src, offset, ts, do_leap)) return; if (clock->sync_offset_direction) @@ -268,6 +271,7 @@ static int do_pps_loop(struct clock *clock, int fd, { int64_t pps_offset, phc_offset, phc_delay; uint64_t pps_ts, phc_ts; + int do_leap; clock->source_label = "pps"; @@ -304,7 +308,10 @@ static int do_pps_loop(struct clock *clock, int fd, pps_offset = pps_ts - phc_ts; } - update_clock(clock, pps_offset, pps_ts, -1); + do_leap = update_sync_offset(clock); + if (do_leap <= 0) + continue; + update_clock(clock, src, pps_offset, pps_ts, -1, do_leap); } close(fd); return 0; @@ -316,6 +323,7 @@ static int do_sysoff_loop(struct clock *clock, clockid_t src, uint64_t ts; int64_t offset, delay; int err = 0, fd = CLOCKID_TO_FD(src); + int do_leap; clock->source_label = "sys"; @@ -325,7 +333,10 @@ static int do_sysoff_loop(struct clock *clock, clockid_t src, err = -1; break; } - update_clock(clock, offset, ts, delay); + do_leap = update_sync_offset(clock); + if (do_leap <= 0) + continue; + update_clock(clock, src, offset, ts, delay, do_leap); } return err; } @@ -335,6 +346,7 @@ static int do_phc_loop(struct clock *clock, clockid_t src, { uint64_t ts; int64_t offset, delay; + int do_leap; clock->source_label = "phc"; @@ -344,7 +356,10 @@ static int do_phc_loop(struct clock *clock, clockid_t src, &offset, &ts, &delay)) { continue; } - update_clock(clock, offset, ts, delay); + do_leap = update_sync_offset(clock); + if (do_leap <= 0) + continue; + update_clock(clock, src, offset, ts, delay, do_leap); } return 0; } @@ -495,10 +510,19 @@ static void close_pmc(struct clock *clock) clock->pmc = NULL; } -static int update_sync_offset(struct clock *clock, int64_t offset, uint64_t ts) +/* Returns: -1 in case of error, 0 for normal sync, 1 to leap clock */ +static int update_sync_offset(struct clock *clock) { + struct timespec tp; + uint64_t ts; int clock_leap; + if (clock_gettime(CLOCK_REALTIME, &tp)) { + pr_err("failed to read clock: %m"); + return -1; + } + ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec; + if (clock->pmc && !(ts > clock->pmc_last_update && ts - clock->pmc_last_update < PMC_UPDATE_INTERVAL)) { @@ -511,9 +535,28 @@ static int update_sync_offset(struct clock *clock, int64_t offset, uint64_t ts) if (!clock->leap && !clock->leap_set) return 0; + clock_leap = leap_second_status(ts, clock->leap_set, + &clock->leap, &clock->sync_offset); + if (clock->leap_set != clock_leap) { + clock->leap_set = clock_leap; + return 1; + } + return 0; +} + +/* Returns: non-zero to skip clock update */ +static int clock_handle_leap(struct clock *clock, clockid_t src, +int64_t o
Re: [Linuxptp-devel] [PATCH 09/14] phc2sys: event subscription
On Mon, 12 May 2014 17:35:18 +0200, Miroslav Lichvar wrote: > One more comment, could you please define the 180 second constant as a > macro near PMC_UPDATE_INTERVAL so it's more clear the two are related > and changing one without other could break things. Good idea. Thanks, Jiri -- Jiri Benc -- "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE Instantly run your Selenium tests across 300+ browser/OS combos. Get unparalleled scalability from the best Selenium testing platform available Simple to use. Nothing to install. Get started now for free." http://p.sf.net/sfu/SauceLabs ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH 11/14] phc2sys: autoconfiguration
On Mon, 12 May 2014 17:25:51 +0200, Miroslav Lichvar wrote: > On Wed, May 07, 2014 at 06:23:15PM +0200, Jiri Benc wrote: > > + do_leap = update_pmc(node, 0); > > Shouldn't the second parameter be "subscriptions > 0"? Yes. Seems it got incorrect during rework of the "Subscription time limit" patch and apparently I haven't tested the new version long enough (unlike the original version). I'll fix it, thanks for catching this. > Also, are you planning to implement some check that would abort/reinit > phc2sys when ptp4l is killed (update_pmc fails to update the UTC > offset or the resubscription fails)? I'm worried it's too easy to get > into a state where phc2sys is not receiving updates and the user is > wondering why it's not working as expected. Yes. I have it on a todo list but as the problem exists with the current code, too (albeit it's much less visible) I don't consider it to be part of this set. Jiri -- Jiri Benc -- "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE Instantly run your Selenium tests across 300+ browser/OS combos. Get unparalleled scalability from the best Selenium testing platform available Simple to use. Nothing to install. Get started now for free." http://p.sf.net/sfu/SauceLabs ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
Re: [Linuxptp-devel] [PATCH] Fix sk_interface_addr().
On Mon, 12 May 2014 18:35:16 +0200, Miroslav Lichvar wrote: > This was broken in commit e804e6, ifa_addr is a pointer to sockaddr, > it shouldn't be referenced for the memcpy call. Oh, my fault, sorry for that and thanks for fixing it. Acked-by: Jiri Benc -- Jiri Benc -- "Accelerate Dev Cycles with Automated Cross-Browser Testing - For FREE Instantly run your Selenium tests across 300+ browser/OS combos. Get unparalleled scalability from the best Selenium testing platform available Simple to use. Nothing to install. Get started now for free." http://p.sf.net/sfu/SauceLabs ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH 14/14] phc2sys: man page update for -a and -r options
Signed-off-by: Jiri Benc --- phc2sys.8 | 115 ++--- 1 files changed, 79 insertions(+), 36 deletions(-) diff --git a/phc2sys.8 b/phc2sys.8 index fa3ae206f3df..37a39d0ba60f 100644 --- a/phc2sys.8 +++ b/phc2sys.8 @@ -1,12 +1,17 @@ .TH PHC2SYS 8 "November 2012" "linuxptp" .SH NAME -phc2sys \- synchronize two clocks +phc2sys \- synchronize two or more clocks .SH SYNOPSIS -.B phc2sys +.B phc2sys \-a [ -.B \-wmqvx +.B \-r ] [ +.B \-r +] [ options ] +.br +.B phc2sys +[ .BI \-d " pps-device" ] [ .BI \-s " device" @@ -15,45 +20,53 @@ phc2sys \- synchronize two clocks ] [ .BI \-O " offset" ] [ -.BI \-E " servo" -] [ -.BI \-P " kp" -] [ -.BI \-I " ki" -] [ -.BI \-S " step" -] [ -.BI \-F " step" -] [ -.BI \-R " update-rate" -] [ -.BI \-N " clock-readings" -] [ -.BI \-L " freq-limit" -] [ -.BI \-u " summary-updates" -] [ -.BI \-n " domain-number" -] [ -.BI \-l " print-level" -] +.BI \-w +] [ options ] .SH DESCRIPTION .B phc2sys -is a program which synchronizes two clocks in the system. Typically, it is used -to synchronize the system clock to a PTP hardware clock (PHC), which itself is -synchronized by the +is a program which synchronizes two or more clocks in the system. Typically, +it is used to synchronize the system clock to a PTP hardware clock (PHC), +which itself is synchronized by the .BR ptp4l (8) program. -Two synchronization modes are supported, one uses a pulse per second (PPS) +With the +.B \-a +option, the clocks to synchronize are fetched from the running +.B ptp4l +daemon and the direction of synchronization automatically follows changes of +the PTP port states. + +Manual configuration is also possible. When using manual configuration, two +synchronization modes are supported, one uses a pulse per second (PPS) signal provided by the source clock and the other mode reads time from the source clock directly. Some clocks can be used in both modes, the mode which -will synchronize the slave clock with better accuracy depends on hardware and -driver implementation. +will synchronize the slave clock with better accuracy depends on hardware +and driver implementation. .SH OPTIONS .TP +.BI \-a +Read the clocks to synchronize from running +.B ptp4l +and follow changes in the port states, adjusting the synchronization +direction automatically. The system clock (CLOCK_REALTIME) is not +synchronized, unless the +.B \-r +option is also specified. +.TP +.BI \-r +Only valid together with the +.B \-a +option. Instructs +.B phc2sys +to also synchronize the system clock (CLOCK_REALTIME). By default, the +system clock is not considered as a possible time source. If you want the +system clock to be eligible to become a time source, specify the +.B \-r +option twice. +.TP .BI \-d " pps-device" Specify the PPS device of the master clock (e.g. /dev/pps0). With this option the PPS synchronization mode is used instead of the direct mode. As the PPS @@ -68,7 +81,10 @@ option the PPS signal of the master clock is enabled automatically, otherwise it has to be enabled before .B phc2sys is started (e.g. by running \f(CWecho 1 > /sys/class/ptp/ptp0/pps_enable\fP). -This option can be used only with the system clock as the slave clock. +This option can be used only with the system clock as the slave clock. Not +compatible with the +.B \-a +option. .TP .BI \-s " device" Specify the master clock by device (e.g. /dev/ptp0) or interface (e.g. eth0) or @@ -76,7 +92,9 @@ by name (e.g. CLOCK_REALTIME for the system clock). When this option is used together with the .B \-d option, the master clock is used only to correct the offset by whole number of -seconds, which cannot be fixed with PPS alone. +seconds, which cannot be fixed with PPS alone. Not compatible with the +.B \-a +option. .TP .BI \-i " interface" Performs the exact same function as @@ -89,7 +107,10 @@ should no longer be used. .TP .BI \-c " device" Specify the slave clock by device (e.g. /dev/ptp1) or interface (e.g. eth1) or -by name. The default is CLOCK_REALTIME (the system clock). +by name. The default is CLOCK_REALTIME (the system clock). Not compatible +with the +.B \-a +option. .TP .BI \-E " servo" Specify which clock servo should be used. Valid values are pi for a PI @@ -128,7 +149,10 @@ minimize the error caused by random delays in scheduling and bus utilization. The default is 5. .TP .BI \-O " offset" -Specify the offset between the slave and master times in seconds. See +Specify the offset between the slave and master times in seconds. Not +compatible with the +.B \-a +option. See .SM .B TIME SCALE USAGE below. @@ -154,7 +178,9 @@ Wait until ptp4l is in a synchronized state. If the .B \-O option is not used, also keep the offse
[Linuxptp-devel] [PATCH 04/14] phc2sys: store information about clocks being UTC or TAI
For now, only CLOCK_REALTIME can be UTC. This may stay this way forever but now we have a clean separation between codepaths where CLOCK_REALTIME is required and codepaths any UTC clock should take. The main motiviation behind this change is removal of sync_offset_direction. It has to be computed on the fly based on the source and destination when we have multiple clocks supported and automatic following of ptp4l state changes implemented. Signed-off-by: Jiri Benc --- phc2sys.c | 60 +--- 1 files changed, 29 insertions(+), 31 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 825d7328af15..6c86b4d9f028 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -130,6 +130,7 @@ struct clock { LIST_ENTRY(clock) list; clockid_t clkid; int sysoff_supported; + int is_utc; struct servo *servo; enum servo_state servo_state; const char *source_label; @@ -146,7 +147,7 @@ struct node { int phc_readings; double phc_interval; int sync_offset; - int sync_offset_direction; + int forced_sync_offset; int leap; int leap_set; int kernel_leap; @@ -161,6 +162,15 @@ static int update_sync_offset(struct node *node); static int clock_handle_leap(struct node *node, struct clock *clock, int64_t offset, uint64_t ts, int do_leap); +static int64_t get_sync_offset(struct node *node, struct clock *src) +{ + int direction = node->forced_sync_offset; + + if (!direction) + direction = node->master->is_utc - src->is_utc; + return (int64_t)node->sync_offset * NS_PER_SEC * direction; +} + static void update_clock_stats(struct clock *clock, unsigned int max_count, int64_t offset, double freq, int64_t delay) { @@ -206,9 +216,7 @@ static void update_clock(struct node *node, struct clock *clock, if (clock_handle_leap(node, clock, offset, ts, do_leap)) return; - if (node->sync_offset_direction) - offset += node->sync_offset * NS_PER_SEC * - node->sync_offset_direction; + offset += get_sync_offset(node, clock); if (clock->sanity_check && clockcheck_sample(clock->sanity_check, ts)) servo_reset(clock->servo); @@ -290,7 +298,7 @@ static int do_pps_loop(struct node *node, struct clock *clock, int fd) if (src == CLOCK_INVALID) { /* The sync offset can't be applied with PPS alone. */ - node->sync_offset_direction = 0; + node->sync_offset = 0; } else { enable_pps_output(node->master->clkid); } @@ -558,15 +566,14 @@ static int clock_handle_leap(struct node *node, struct clock *clock, if (!node->leap && !do_leap) return 0; - if (clock->clkid != CLOCK_REALTIME && - node->master->clkid != CLOCK_REALTIME) + if (clock->is_utc == node->master->is_utc) return 0; /* If the system clock is the master clock, get a time stamp from it, as it is the clock which will include the leap second. */ - if (node->master->clkid == CLOCK_REALTIME) { + if (node->master->is_utc) { struct timespec tp; - if (clock_gettime(CLOCK_REALTIME, &tp)) { + if (clock_gettime(node->master->clkid, &tp)) { pr_err("failed to read clock: %m"); return -1; } @@ -575,11 +582,8 @@ static int clock_handle_leap(struct node *node, struct clock *clock, /* If the clock will be stepped, the time stamp has to be the target time. Ignore possible 1 second error in UTC offset. */ - if (clock->clkid == CLOCK_REALTIME && - clock->servo_state == SERVO_UNLOCKED) { - ts -= offset + node->sync_offset * NS_PER_SEC * - node->sync_offset_direction; - } + if (clock->is_utc && clock->servo_state == SERVO_UNLOCKED) + ts -= get_sync_offset(node, clock); /* Suspend clock updates in the last second before midnight. */ if (is_utc_ambiguous(ts)) { @@ -610,10 +614,12 @@ static int clock_add(struct node *node, clockid_t clkid) c->clkid = clkid; c->servo_state = SERVO_UNLOCKED; - if (c->clkid == CLOCK_REALTIME) + if (c->clkid == CLOCK_REALTIME) { c->source_label = "sys"; - else + c->is_utc = 1; + } else { c->source_label = "phc"; + } if (node->stats_max_count > 0) { c->offset_stats = stats_create(); @@ -698,7 +704,7 @@ int main(int argc, cha
[Linuxptp-devel] [PATCH 12/14] phc2sys: autoconfigure realtime clock on demand only
By default, do not synchronize CLOCK_REALTIME. To do it, -r option is needed. That will only consider CLOCK_REALTIME as the destination. To consider it also as a possible time source, use -rr. Signed-off-by: Jiri Benc --- phc2sys.c | 31 --- 1 files changed, 24 insertions(+), 7 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index d102ca8e8d93..29916a59f2a5 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -67,6 +67,7 @@ struct clock { clockid_t clkid; int sysoff_supported; int is_utc; + int dest_only; int state; int new_state; struct servo *servo; @@ -323,10 +324,16 @@ static void reconfigure(struct node *node) node->master = NULL; return; } + if ((!src_cnt && (!rt || rt->dest_only)) || + (!dst_cnt && !rt)) { + pr_info("nothing to synchronize"); + node->master = NULL; + return; + } if (!src_cnt) { src = rt; rt->state = PS_SLAVE; - } else { + } else if (rt) { if (rt->state != PS_MASTER) { rt->state = PS_MASTER; clock_reinit(rt); @@ -921,7 +928,7 @@ static void close_pmc(struct node *node) node->pmc = NULL; } -static int auto_init_ports(struct node *node) +static int auto_init_ports(struct node *node, int add_rt) { struct port *port; struct clock *clock; @@ -976,8 +983,13 @@ static int auto_init_ports(struct node *node) } node->state_changed = 1; - if (!clock_add(node, "CLOCK_REALTIME")) - return -1; + if (add_rt) { + clock = clock_add(node, "CLOCK_REALTIME"); + if (!clock) + return -1; + if (add_rt == 1) + clock->dest_only = 1; + } /* get initial offset */ if (run_pmc_get_utc_offset(node, 1000) <= 0) { @@ -1072,6 +1084,8 @@ static void usage(char *progname) "\n" " automatic configuration:\n" " -a turn on autoconfiguration\n" + " -r synchronize system (realtime) clock\n" + "repeat -r to consider it also as a time source\n" " manual configuration:\n" " -c [dev|name] slave clock (CLOCK_REALTIME)\n" " -d [dev] master PPS device\n" @@ -1104,7 +1118,7 @@ int main(int argc, char *argv[]) char *progname; char *src_name = NULL, *dst_name = NULL; struct clock *src, *dst; - int autocfg = 0; + int autocfg = 0, rt = 0; int c, domain_number = 0, pps_fd = -1; int r, wait_sync = 0; int print_level = LOG_INFO, use_syslog = 1, verbose = 0; @@ -1124,11 +1138,14 @@ int main(int argc, char *argv[]) progname = strrchr(argv[0], '/'); progname = progname ? 1+progname : argv[0]; while (EOF != (c = getopt(argc, argv, - "ac:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xl:mqvh"))) { + "arc:d:s:E:P:I:S:F:R:N:O:L:i:u:wn:xl:mqvh"))) { switch (c) { case 'a': autocfg = 1; break; + case 'r': + rt++; + break; case 'c': dst_name = strdup(optarg); break; @@ -1258,7 +1275,7 @@ int main(int argc, char *argv[]) if (autocfg) { if (init_pmc(&node, domain_number)) return -1; - if (auto_init_ports(&node) < 0) + if (auto_init_ports(&node, rt) < 0) return -1; return do_loop(&node, 1); } -- 1.7.6.5 -- Is your legacy SCM system holding you back? Join Perforce May 7 to find out: • 3 signs your SCM is hindering your productivity • Requirements for releasing software faster • Expert tips and advice for migrating your SCM now http://p.sf.net/sfu/perforce ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH 13/14] phc2sys: check clockIdentity
Make sure that we handle only one PTP clock (node). This is for an extra safety. Signed-off-by: Jiri Benc --- phc2sys.c | 44 ++-- 1 files changed, 42 insertions(+), 2 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 29916a59f2a5..d71422047df2 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -102,6 +102,8 @@ struct node { int pmc_ds_requested; uint64_t pmc_last_update; int state_changed; + int clock_identity_set; + struct ClockIdentity clock_identity; LIST_HEAD(port_head, port) ports; LIST_HEAD(clock_head, clock) clocks; struct clock *master; @@ -607,6 +609,15 @@ static int do_loop(struct node *node, int subscriptions) return 0; /* unreachable */ } +static int check_clock_identity(struct node *node, struct ptp_message *msg) +{ + if (!node->clock_identity_set) + return 1; + return !memcmp(&node->clock_identity, + &msg->header.sourcePortIdentity.clockIdentity, + sizeof(struct ClockIdentity)); +} + static int is_msg_mgt(struct ptp_message *msg) { struct TLV *tlv; @@ -784,6 +795,12 @@ static int run_pmc(struct node *node, int timeout, int ds_id, if (!*msg) continue; + if (!check_clock_identity(node, *msg)) { + msg_put(*msg); + *msg = NULL; + continue; + } + res = is_msg_mgt(*msg); if (res < 0 && get_mgt_err_id(*msg) == ds_id) { node->pmc_ds_requested = 0; @@ -922,6 +939,24 @@ out: return res; } +static int run_pmc_clock_identity(struct node *node, int timeout) +{ + struct ptp_message *msg; + struct defaultDS *dds; + int res; + + res = run_pmc(node, timeout, DEFAULT_DATA_SET, &msg); + if (res <= 0) + return res; + + dds = (struct defaultDS *)get_mgt_data(msg); + memcpy(&node->clock_identity, &dds->clockIdentity, + sizeof(struct ClockIdentity)); + node->clock_identity_set = 1; + msg_put(msg); + return 1; +} + static void close_pmc(struct node *node) { pmc_destroy(node->pmc); @@ -938,7 +973,7 @@ static int auto_init_ports(struct node *node, int add_rt) char iface[IFNAMSIZ]; while (1) { - res = run_pmc_get_number_ports(node, 1000); + res = run_pmc_clock_identity(node, 1000); if (res < 0) return -1; if (res > 0) @@ -946,7 +981,12 @@ static int auto_init_ports(struct node *node, int add_rt) /* res == 0, timeout */ pr_notice("Waiting for ptp4l..."); } - number_ports = res; + + number_ports = run_pmc_get_number_ports(node, 1000); + if (number_ports <= 0) { + pr_err("failed to get number of ports"); + return -1; + } res = run_pmc_subscribe(node, 1000); if (res <= 0) { -- 1.7.6.5 -- Is your legacy SCM system holding you back? Join Perforce May 7 to find out: • 3 signs your SCM is hindering your productivity • Requirements for releasing software faster • Expert tips and advice for migrating your SCM now http://p.sf.net/sfu/perforce ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH 01/14] phc2sys: generalize run_pmc
Make run_pmc usable for any kind of management message. Create wrappers for waiting for ptp4l and for getting UTC offset. Signed-off-by: Jiri Benc --- phc2sys.c | 131 +++-- 1 files changed, 66 insertions(+), 65 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 5ecb602120c3..0581eb5bcb24 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -141,7 +141,6 @@ struct clock { int leap_set; int kernel_leap; struct pmc *pmc; - int pmc_ds_idx; int pmc_ds_requested; uint64_t pmc_last_update; struct clockcheck *sanity_check; @@ -390,31 +389,14 @@ static int init_pmc(struct clock *clock, int domain_number) return 0; } -static int run_pmc(struct clock *clock, int timeout, - int wait_sync, int get_utc_offset) +static int run_pmc(struct clock *clock, int timeout, int ds_id, + struct ptp_message **msg) { - struct ptp_message *msg; - struct timePropertiesDS *tds; - void *data; #define N_FD 1 struct pollfd pollfd[N_FD]; - int cnt, ds_done; -#define N_ID 2 - int ds_ids[N_ID] = { - PORT_DATA_SET, - TIME_PROPERTIES_DATA_SET - }; - - while (clock->pmc_ds_idx < N_ID) { - /* Check if the data set is really needed. */ - if ((ds_ids[clock->pmc_ds_idx] == PORT_DATA_SET && -!wait_sync) || - (ds_ids[clock->pmc_ds_idx] == TIME_PROPERTIES_DATA_SET && -!get_utc_offset)) { - clock->pmc_ds_idx++; - continue; - } + int cnt; + while (1) { pollfd[0].fd = pmc_get_transport_fd(clock->pmc); pollfd[0].events = POLLIN|POLLPRI; if (!clock->pmc_ds_requested) @@ -434,62 +416,76 @@ static int run_pmc(struct clock *clock, int timeout, /* Send a new request if there are no pending messages. */ if ((pollfd[0].revents & POLLOUT) && !(pollfd[0].revents & (POLLIN|POLLPRI))) { - pmc_send_get_action(clock->pmc, - ds_ids[clock->pmc_ds_idx]); + pmc_send_get_action(clock->pmc, ds_id); clock->pmc_ds_requested = 1; } if (!(pollfd[0].revents & (POLLIN|POLLPRI))) continue; - msg = pmc_recv(clock->pmc); + *msg = pmc_recv(clock->pmc); - if (!msg) + if (!*msg) continue; - if (!is_msg_mgt(msg) || - get_mgt_id(msg) != ds_ids[clock->pmc_ds_idx]) { - msg_put(msg); + if (!is_msg_mgt(*msg) || + get_mgt_id(*msg) != ds_id) { + msg_put(*msg); + *msg = NULL; continue; } + clock->pmc_ds_requested = 0; + return 1; + } +} - data = get_mgt_data(msg); - ds_done = 0; - - switch (get_mgt_id(msg)) { - case PORT_DATA_SET: - switch (((struct portDS *)data)->portState) { - case PS_MASTER: - case PS_SLAVE: - ds_done = 1; - break; - } +static int run_pmc_wait_sync(struct clock *clock, int timeout) +{ + struct ptp_message *msg; + int res; + void *data; + Enumeration8 portState; - break; - case TIME_PROPERTIES_DATA_SET: - tds = (struct timePropertiesDS *)data; - if (tds->flags & PTP_TIMESCALE) { - clock->sync_offset = tds->currentUtcOffset; - if (tds->flags & LEAP_61) - clock->leap = 1; - else if (tds->flags & LEAP_59) - clock->leap = -1; - else - clock->leap = 0; - } - ds_done = 1; - break; - } + while (1) { + res = run_pmc(clock, timeout, PORT_DATA_SET, &msg); + if (res <= 0) + return res; - if (ds_done) { - /* Proceed with the next data set. */ - clock->pmc_ds_idx++; - clock->pmc_ds_requested = 0; - } + data = get_mgt_data(msg); + port
[Linuxptp-devel] [PATCH 09/14] phc2sys: event subscription
Add support for subscribing to events (run_pmc_subscribe) and receiving and handling of received events (run_pmc_events). Add initial support for port status changes. Signed-off-by: Jiri Benc --- phc2sys.c | 111 +++- 1 files changed, 109 insertions(+), 2 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index ece4560e0c67..f7af1b26451b 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -41,6 +41,7 @@ #include "ds.h" #include "fsm.h" #include "missing.h" +#include "notification.h" #include "phc.h" #include "pi.h" #include "pmc_common.h" @@ -65,6 +66,8 @@ struct clock { clockid_t clkid; int sysoff_supported; int is_utc; + int state; + int new_state; struct servo *servo; enum servo_state servo_state; char *device; @@ -78,6 +81,7 @@ struct clock { struct port { LIST_ENTRY(port) list; unsigned int number; + int state; struct clock *clock; }; @@ -95,6 +99,7 @@ struct node { struct pmc *pmc; int pmc_ds_requested; uint64_t pmc_last_update; + int state_changed; LIST_HEAD(port_head, port) ports; LIST_HEAD(clock_head, clock) clocks; struct clock *master; @@ -533,6 +538,81 @@ static void *get_mgt_data(struct ptp_message *msg) return mgt->data; } +static int normalize_state(int state) +{ + if (state != PS_MASTER && state != PS_SLAVE && + state != PS_PRE_MASTER && state != PS_UNCALIBRATED) { + /* treat any other state as "not a master nor a slave" */ + state = PS_DISABLED; + } + return state; +} + +static int clock_compute_state(struct node *node, struct clock *clock) +{ + struct port *p; + int state = PS_DISABLED; + + LIST_FOREACH(p, &node->ports, list) { + if (p->clock != clock) + continue; + /* PS_SLAVE takes the highest precedence, PS_UNCALIBRATED +* after that, PS_MASTER is third, PS_PRE_MASTER fourth and +* all of that overrides PS_DISABLED, which corresponds +* nicely with the numerical values */ + if (p->state > state) + state = p->state; + } + return state; +} + +static int recv_subscribed(struct node *node, struct ptp_message *msg, + int excluded) +{ + int mgt_id, state; + struct portDS *pds; + struct port *port; + struct clock *clock; + + mgt_id = get_mgt_id(msg); + if (mgt_id == excluded) + return 0; + switch (mgt_id) { + case PORT_DATA_SET: + pds = get_mgt_data(msg); + port = port_get(node, pds->portIdentity.portNumber); + if (!port) { + pr_info("received data for unknown port %s", + pid2str(&pds->portIdentity)); + return 1; + } + state = normalize_state(pds->portState); + if (port->state != state) { + pr_info("port %s changed state", + pid2str(&pds->portIdentity)); + port->state = state; + clock = port->clock; + state = clock_compute_state(node, clock); + if (clock->state != state) { + clock->new_state = state; + node->state_changed = 1; + } + } + return 1; + } + return 0; +} + +static void send_subscription(struct node *node) +{ + struct subscribe_events_np sen; + + memset(&sen, 0, sizeof(sen)); + sen.duration = 180; /* 3 minutes */ + sen.bitmask[0] = 1 << NOTIFY_PORT_STATE; + pmc_send_set_action(node->pmc, SUBSCRIBE_EVENTS_NP, &sen, sizeof(sen)); +} + static int init_pmc(struct node *node, int domain_number) { node->pmc = pmc_create(TRANS_UDS, "/var/run/phc2sys", 0, @@ -555,7 +635,7 @@ static int run_pmc(struct node *node, int timeout, int ds_id, while (1) { pollfd[0].fd = pmc_get_transport_fd(node->pmc); pollfd[0].events = POLLIN|POLLPRI; - if (!node->pmc_ds_requested) + if (!node->pmc_ds_requested && ds_id >= 0) pollfd[0].events |= POLLOUT; cnt = poll(pollfd, N_FD, timeout); @@ -572,7 +652,14 @@ static int run_pmc(struct node *node, int timeout, int ds_id, /* Send a new request if there are no pending messages. */ if ((pollfd[0].rev
[Linuxptp-devel] [PATCH 10/14] phc2sys: propagate received errors
Recognize errors returned in MANAGEMENT_ERROR_STATUS TLV and return a distinct value from run_pmc in case such error is received. Signed-off-by: Jiri Benc --- phc2sys.c | 34 +++--- 1 files changed, 27 insertions(+), 7 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index f7af1b26451b..731c2bb1af35 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -521,9 +521,11 @@ static int is_msg_mgt(struct ptp_message *msg) if (msg->tlv_count != 1) return 0; tlv = (struct TLV *) msg->management.suffix; - if (tlv->type != TLV_MANAGEMENT) - return 0; - return 1; + if (tlv->type == TLV_MANAGEMENT) + return 1; + if (tlv->type == TLV_MANAGEMENT_ERROR_STATUS) + return -1; + return 0; } static int get_mgt_id(struct ptp_message *msg) @@ -538,6 +540,14 @@ static void *get_mgt_data(struct ptp_message *msg) return mgt->data; } +static int get_mgt_err_id(struct ptp_message *msg) +{ + struct management_error_status *mgt; + + mgt = (struct management_error_status *)msg->management.suffix; + return mgt->id; +} + static int normalize_state(int state) { if (state != PS_MASTER && state != PS_SLAVE && @@ -625,12 +635,18 @@ static int init_pmc(struct node *node, int domain_number) return 0; } +/* Return values: + * 1: success + * 0: timeout + * -1: error reported by the other side + * -2: local error, fatal + */ static int run_pmc(struct node *node, int timeout, int ds_id, struct ptp_message **msg) { #define N_FD 1 struct pollfd pollfd[N_FD]; - int cnt; + int cnt, res; while (1) { pollfd[0].fd = pmc_get_transport_fd(node->pmc); @@ -641,7 +657,7 @@ static int run_pmc(struct node *node, int timeout, int ds_id, cnt = poll(pollfd, N_FD, timeout); if (cnt < 0) { pr_err("poll failed"); - return -1; + return -2; } if (!cnt) { /* Request the data set again in the next run. */ @@ -671,8 +687,12 @@ static int run_pmc(struct node *node, int timeout, int ds_id, if (!*msg) continue; - if (!is_msg_mgt(*msg) || - recv_subscribed(node, *msg, ds_id) || + res = is_msg_mgt(*msg); + if (res < 0 && get_mgt_err_id(*msg) == ds_id) { + node->pmc_ds_requested = 0; + return -1; + } + if (res <= 0 || recv_subscribed(node, *msg, ds_id) || get_mgt_id(*msg) != ds_id) { msg_put(*msg); *msg = NULL; -- 1.7.6.5 -- Is your legacy SCM system holding you back? Join Perforce May 7 to find out: • 3 signs your SCM is hindering your productivity • Requirements for releasing software faster • Expert tips and advice for migrating your SCM now http://p.sf.net/sfu/perforce ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH 08/14] pmc_common: easy way to set port and broadcast target
Implement pmc_target_port to set a port number, leaving clock identity unchanged, and pmc_target_all to set clock identity and port number to all 1's. Signed-off-by: Jiri Benc --- pmc_common.c | 12 +++- pmc_common.h |2 ++ 2 files changed, 13 insertions(+), 1 deletions(-) diff --git a/pmc_common.c b/pmc_common.c index 2c75074c8fb7..41385da45209 100644 --- a/pmc_common.c +++ b/pmc_common.c @@ -78,7 +78,7 @@ struct pmc *pmc_create(enum transport_type transport_type, const char *iface_nam goto failed; } pmc->port_identity.portNumber = 1; - memset(&pmc->target, 0xff, sizeof(pmc->target)); + pmc_target_all(pmc); pmc->boundary_hops = boundary_hops; pmc->domain_number = domain_number; @@ -325,3 +325,13 @@ int pmc_target(struct pmc *pmc, struct PortIdentity *pid) pmc->target = *pid; return 0; } + +void pmc_target_port(struct pmc *pmc, UInteger16 portNumber) +{ + pmc->target.portNumber = portNumber; +} + +void pmc_target_all(struct pmc *pmc) +{ + memset(&pmc->target, 0xff, sizeof(pmc->target)); +} diff --git a/pmc_common.h b/pmc_common.h index 9fcb51da3fd4..9adb9d1dd98b 100644 --- a/pmc_common.h +++ b/pmc_common.h @@ -41,5 +41,7 @@ int pmc_send_set_action(struct pmc *pmc, int id, void *data, int datasize); struct ptp_message *pmc_recv(struct pmc *pmc); int pmc_target(struct pmc *pmc, struct PortIdentity *pid); +void pmc_target_port(struct pmc *pmc, UInteger16 portNumber); +void pmc_target_all(struct pmc *pmc); #endif -- 1.7.6.5 -- Is your legacy SCM system holding you back? Join Perforce May 7 to find out: • 3 signs your SCM is hindering your productivity • Requirements for releasing software faster • Expert tips and advice for migrating your SCM now http://p.sf.net/sfu/perforce ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH 03/14] phc2sys: split clock and node
Split members that apply to all synchronized clocks and members that apply to an individual clock. Keep all clocks in a list, with a pointer to the source clock. This will allow to support multiple clocks synchronization. Signed-off-by: Jiri Benc --- phc2sys.c | 397 +--- 1 files changed, 218 insertions(+), 179 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 19dce45964eb..825d7328af15 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -60,9 +61,6 @@ #define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC) struct clock; -static int update_sync_offset(struct clock *clock); -static int clock_handle_leap(struct clock *clock, clockid_t src, -int64_t offset, uint64_t ts, int do_leap); static clockid_t clock_open(char *device) { @@ -129,14 +127,24 @@ static int read_phc(clockid_t clkid, clockid_t sysclk, int readings, } struct clock { + LIST_ENTRY(clock) list; clockid_t clkid; + int sysoff_supported; struct servo *servo; enum servo_state servo_state; const char *source_label; struct stats *offset_stats; struct stats *freq_stats; struct stats *delay_stats; + struct clockcheck *sanity_check; +}; + +struct node { unsigned int stats_max_count; + int sanity_freq_limit; + enum servo_type servo_type; + int phc_readings; + double phc_interval; int sync_offset; int sync_offset_direction; int leap; @@ -145,10 +153,15 @@ struct clock { struct pmc *pmc; int pmc_ds_requested; uint64_t pmc_last_update; - struct clockcheck *sanity_check; + LIST_HEAD(clock_head, clock) clocks; + struct clock *master; }; -static void update_clock_stats(struct clock *clock, +static int update_sync_offset(struct node *node); +static int clock_handle_leap(struct node *node, struct clock *clock, +int64_t offset, uint64_t ts, int do_leap); + +static void update_clock_stats(struct clock *clock, unsigned int max_count, int64_t offset, double freq, int64_t delay) { struct stats_result offset_stats, freq_stats, delay_stats; @@ -158,7 +171,7 @@ static void update_clock_stats(struct clock *clock, if (delay >= 0) stats_add_value(clock->delay_stats, delay); - if (stats_get_num_values(clock->offset_stats) < clock->stats_max_count) + if (stats_get_num_values(clock->offset_stats) < max_count) return; stats_get_result(clock->offset_stats, &offset_stats); @@ -183,19 +196,19 @@ static void update_clock_stats(struct clock *clock, stats_reset(clock->delay_stats); } -static void update_clock(struct clock *clock, clockid_t src, +static void update_clock(struct node *node, struct clock *clock, int64_t offset, uint64_t ts, int64_t delay, int do_leap) { enum servo_state state; double ppb; - if (clock_handle_leap(clock, src, offset, ts, do_leap)) + if (clock_handle_leap(node, clock, offset, ts, do_leap)) return; - if (clock->sync_offset_direction) - offset += clock->sync_offset * NS_PER_SEC * - clock->sync_offset_direction; + if (node->sync_offset_direction) + offset += node->sync_offset * NS_PER_SEC * + node->sync_offset_direction; if (clock->sanity_check && clockcheck_sample(clock->sanity_check, ts)) servo_reset(clock->servo); @@ -221,15 +234,15 @@ static void update_clock(struct clock *clock, clockid_t src, } if (clock->offset_stats) { - update_clock_stats(clock, offset, ppb, delay); + update_clock_stats(clock, node->stats_max_count, offset, ppb, delay); } else { if (delay >= 0) { pr_info("%s offset %9" PRId64 " s%d freq %+7.0f " "delay %6" PRId64, - clock->source_label, offset, state, ppb, delay); + node->master->source_label, offset, state, ppb, delay); } else { pr_info("%s offset %9" PRId64 " s%d freq %+7.0f", - clock->source_label, offset, state, ppb); + node->master->source_label, offset, state, ppb); } } } @@ -266,20 +279,20 @@ static int read_pps(int fd, int64_t *offset, uint64_t *ts) return 1; } -static int do_pps_loop(struct clock *clock, int fd, - clockid_t src, int n_readings)
[Linuxptp-devel] [PATCH 00/14] automatic phc2sys configuration, phc2sys part
This is the phc2sys part of the autoconfig patchset. It uses the event subscription mechanism implemented in ptp4l. The patchset is prepared to handle the "emulated boundary clock" scenario, i.e. ptp4l working over multiple PHC's. I have old patches to do that (the dynamic port allocation patchset + patchset to support multiple PHC's) which I'll rebase on top of this and post after the patchset is accepted. Jiri Jiri Benc (14): phc2sys: generalize run_pmc phc2sys: split update_sync_offset phc2sys: split clock and node phc2sys: store information about clocks being UTC or TAI phc2sys: rearrange declarations phc2sys: open devices in clock_add phc2sys: track ports pmc_common: easy way to set port and broadcast target phc2sys: event subscription phc2sys: propagate received errors phc2sys: autoconfiguration phc2sys: autoconfigure realtime clock on demand only phc2sys: check clockIdentity phc2sys: man page update for -a and -r options phc2sys.8| 115 +-- phc2sys.c| 1076 -- pmc_common.c | 12 +- pmc_common.h |2 + 4 files changed, 908 insertions(+), 297 deletions(-) -- 1.7.6.5 -- Is your legacy SCM system holding you back? Join Perforce May 7 to find out: • 3 signs your SCM is hindering your productivity • Requirements for releasing software faster • Expert tips and advice for migrating your SCM now http://p.sf.net/sfu/perforce ___ Linuxptp-devel mailing list Linuxptp-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linuxptp-devel
[Linuxptp-devel] [PATCH 02/14] phc2sys: split update_sync_offset
Split the generic (global) part of update_sync_offset and the part that affects individual clocks. This is in preparation for phc2sys handling synchronization of more clocks. Signed-off-by: Jiri Benc --- phc2sys.c | 71 +++- 1 files changed, 55 insertions(+), 16 deletions(-) diff --git a/phc2sys.c b/phc2sys.c index 0581eb5bcb24..19dce45964eb 100644 --- a/phc2sys.c +++ b/phc2sys.c @@ -60,7 +60,9 @@ #define PMC_UPDATE_INTERVAL (60 * NS_PER_SEC) struct clock; -static int update_sync_offset(struct clock *clock, int64_t offset, uint64_t ts); +static int update_sync_offset(struct clock *clock); +static int clock_handle_leap(struct clock *clock, clockid_t src, +int64_t offset, uint64_t ts, int do_leap); static clockid_t clock_open(char *device) { @@ -181,13 +183,14 @@ static void update_clock_stats(struct clock *clock, stats_reset(clock->delay_stats); } -static void update_clock(struct clock *clock, -int64_t offset, uint64_t ts, int64_t delay) +static void update_clock(struct clock *clock, clockid_t src, +int64_t offset, uint64_t ts, int64_t delay, +int do_leap) { enum servo_state state; double ppb; - if (update_sync_offset(clock, offset, ts)) + if (clock_handle_leap(clock, src, offset, ts, do_leap)) return; if (clock->sync_offset_direction) @@ -268,6 +271,7 @@ static int do_pps_loop(struct clock *clock, int fd, { int64_t pps_offset, phc_offset, phc_delay; uint64_t pps_ts, phc_ts; + int do_leap; clock->source_label = "pps"; @@ -304,7 +308,10 @@ static int do_pps_loop(struct clock *clock, int fd, pps_offset = pps_ts - phc_ts; } - update_clock(clock, pps_offset, pps_ts, -1); + do_leap = update_sync_offset(clock); + if (do_leap <= 0) + continue; + update_clock(clock, src, pps_offset, pps_ts, -1, do_leap); } close(fd); return 0; @@ -316,6 +323,7 @@ static int do_sysoff_loop(struct clock *clock, clockid_t src, uint64_t ts; int64_t offset, delay; int err = 0, fd = CLOCKID_TO_FD(src); + int do_leap; clock->source_label = "sys"; @@ -325,7 +333,10 @@ static int do_sysoff_loop(struct clock *clock, clockid_t src, err = -1; break; } - update_clock(clock, offset, ts, delay); + do_leap = update_sync_offset(clock); + if (do_leap <= 0) + continue; + update_clock(clock, src, offset, ts, delay, do_leap); } return err; } @@ -335,6 +346,7 @@ static int do_phc_loop(struct clock *clock, clockid_t src, { uint64_t ts; int64_t offset, delay; + int do_leap; clock->source_label = "phc"; @@ -344,7 +356,10 @@ static int do_phc_loop(struct clock *clock, clockid_t src, &offset, &ts, &delay)) { continue; } - update_clock(clock, offset, ts, delay); + do_leap = update_sync_offset(clock); + if (do_leap <= 0) + continue; + update_clock(clock, src, offset, ts, delay, do_leap); } return 0; } @@ -495,10 +510,19 @@ static void close_pmc(struct clock *clock) clock->pmc = NULL; } -static int update_sync_offset(struct clock *clock, int64_t offset, uint64_t ts) +/* Returns: -1 in case of error, 0 for normal sync, 1 to leap clock */ +static int update_sync_offset(struct clock *clock) { + struct timespec tp; + uint64_t ts; int clock_leap; + if (clock_gettime(CLOCK_REALTIME, &tp)) { + pr_err("failed to read clock: %m"); + return -1; + } + ts = tp.tv_sec * NS_PER_SEC + tp.tv_nsec; + if (clock->pmc && !(ts > clock->pmc_last_update && ts - clock->pmc_last_update < PMC_UPDATE_INTERVAL)) { @@ -511,9 +535,28 @@ static int update_sync_offset(struct clock *clock, int64_t offset, uint64_t ts) if (!clock->leap && !clock->leap_set) return 0; + clock_leap = leap_second_status(ts, clock->leap_set, + &clock->leap, &clock->sync_offset); + if (clock->leap_set != clock_leap) { + clock->leap_set = clock_leap; + return 1; + } + return 0; +} + +/* Returns: non-zero to skip clock update */ +static int clock_handle_leap(struct clock *clock, clockid_t src, +int64_t o