This puts groundwork for event subscription and notification. The individual events are added by subsequent patches.
Signed-off-by: Jiri Benc <jb...@redhat.com> --- clock.c | 136 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ clock.h | 11 +++++ notification.h | 27 +++++++++++ tlv.c | 4 ++ tlv.h | 8 +++ 5 files changed, 186 insertions(+), 0 deletions(-) create mode 100644 notification.h diff --git a/clock.c b/clock.c index a85efdec2857..600fc058a391 100644 --- a/clock.c +++ b/clock.c @@ -22,6 +22,7 @@ #include <string.h> #include <time.h> +#include "address.h" #include "bmc.h" #include "clock.h" #include "clockadj.h" @@ -59,6 +60,14 @@ struct clock_stats { unsigned int max_count; }; +struct clock_subscriber { + LIST_ENTRY(clock_subscriber) list; + uint8_t events[EVENT_BITMASK_CNT]; + struct PortIdentity targetPortIdentity; + struct address addr; + UInteger16 sequenceId; +}; + struct clock { clockid_t clkid; struct servo *servo; @@ -99,6 +108,7 @@ struct clock { int stats_interval; struct clockcheck *sanity_check; struct interface uds_interface; + LIST_HEAD(clock_subscribers_head, clock_subscriber) subscribers; }; struct clock the_clock; @@ -110,9 +120,96 @@ static int cid_eq(struct ClockIdentity *a, struct ClockIdentity *b) return 0 == memcmp(a, b, sizeof(*a)); } +#ifndef LIST_FOREACH_SAFE +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) && ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) +#endif + +static void remove_subscriber(struct clock_subscriber *s) +{ + LIST_REMOVE(s, list); + free(s); +} + +static void clock_update_subscription(struct clock *c, struct ptp_message *req, + uint8_t *bitmask) +{ + struct clock_subscriber *s; + int i, remove = 1; + + for (i = 0; i < EVENT_BITMASK_CNT; i++) { + if (bitmask[i]) { + remove = 0; + break; + } + } + + LIST_FOREACH(s, &c->subscribers, list) { + if (!memcmp(&s->targetPortIdentity, &req->header.sourcePortIdentity, + sizeof(struct PortIdentity))) { + /* Found, update the transport address and event + * mask. */ + if (!remove) { + s->addr = req->address; + memcpy(s->events, bitmask, EVENT_BITMASK_CNT); + } else { + remove_subscriber(s); + } + return; + } + } + if (remove) + return; + /* Not present yet, add the subscriber. */ + s = malloc(sizeof(*s)); + if (!s) { + pr_err("failed to allocate memory for a subscriber"); + return; + } + s->targetPortIdentity = req->header.sourcePortIdentity; + s->addr = req->address; + memcpy(s->events, bitmask, EVENT_BITMASK_CNT); + s->sequenceId = 0; + LIST_INSERT_HEAD(&c->subscribers, s, list); +} + +static void clock_flush_subscriptions(struct clock *c) +{ + struct clock_subscriber *s, *tmp; + + LIST_FOREACH_SAFE(s, &c->subscribers, list, tmp) { + remove_subscriber(s); + } +} + +void clock_send_notification(struct clock *c, struct ptp_message *msg, + int msglen, enum notification event) +{ + unsigned int event_pos = event / 8; + uint8_t mask = 1 << (event % 8); + struct port *uds = c->port[c->nports]; + struct clock_subscriber *s; + + LIST_FOREACH(s, &c->subscribers, list) { + if (!(s->events[event_pos] & mask)) + continue; + /* send event */ + msg->header.sequenceId = htons(s->sequenceId); + s->sequenceId++; + msg->management.targetPortIdentity.clockIdentity = s->targetPortIdentity.clockIdentity; + msg->management.targetPortIdentity.portNumber = htons(s->targetPortIdentity.portNumber); + msg->address = s->addr; + port_forward_to(uds, msg); + } +} + void clock_destroy(struct clock *c) { int i; + + clock_flush_subscriptions(c); for (i = 0; i < c->nports; i++) { port_close(c->port[i]); close(c->fault_fd[i]); @@ -328,6 +425,40 @@ static int clock_management_set(struct clock *c, struct port *p, return respond ? 1 : 0; } +static int clock_management_cmd_response(struct clock *c, struct port *p, + int id, struct ptp_message *req) +{ + int respond = 0; + struct ptp_message *rsp = NULL; + struct management_tlv *tlv; + struct subscribe_events_np *sen; + + tlv = (struct management_tlv *)req->management.suffix; + + switch (id) { + case SUBSCRIBE_EVENTS_NP: + if (p != c->port[c->nports]) { + /* Only the UDS port allowed. */ + break; + } + sen = (struct subscribe_events_np *)tlv->data; + clock_update_subscription(c, req, sen->bitmask); + respond = 1; + break; + } + if (respond) { + rsp = port_management_reply(port_identity(p), p, req); + if (!rsp) { + pr_err("failed to allocate response message"); + return 1; + } + if (port_prepare_and_send(p, rsp, 0)) + pr_err("failed to send response message"); + msg_put(rsp); + } + return respond ? 1 : 0; +} + static void clock_stats_update(struct clock_stats *s, int64_t offset, double freq) { @@ -669,6 +800,8 @@ struct clock *clock_create(int phc_index, struct interface *iface, int count, clock_sync_interval(c, 0); + LIST_INIT(&c->subscribers); + for (i = 0; i < count; i++) { c->port[i] = port_open(phc_index, timestamping, 1+i, &iface[i], c); if (!c->port[i]) { @@ -842,6 +975,8 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg) return changed; break; case COMMAND: + if (clock_management_cmd_response(c, p, mgt->id, msg)) + return changed; break; default: return changed; @@ -880,6 +1015,7 @@ int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg) case PRIMARY_DOMAIN: case TIME_STATUS_NP: case GRANDMASTER_SETTINGS_NP: + case SUBSCRIBE_EVENTS_NP: clock_management_send_error(p, msg, NOT_SUPPORTED); break; default: diff --git a/clock.h b/clock.h index 804640bdb8f4..8718f2db715b 100644 --- a/clock.h +++ b/clock.h @@ -23,6 +23,7 @@ #include "dm.h" #include "ds.h" #include "config.h" +#include "notification.h" #include "servo.h" #include "tlv.h" #include "tmv.h" @@ -134,6 +135,16 @@ void clock_install_fda(struct clock *c, struct port *p, struct fdarray fda); int clock_manage(struct clock *c, struct port *p, struct ptp_message *msg); /** + * Send notification about an event to all subscribers. + * @param c The clock instance. + * @param msg The PTP message to send, in network byte order. + * @param msglen The length of the message in bytes. + * @param event The event that occured. + */ +void clock_send_notification(struct clock *c, struct ptp_message *msg, + int msglen, enum notification event); + +/** * Obtain a clock's parent data set. * @param c The clock instance. * @return A pointer to the parent data set of the clock. diff --git a/notification.h b/notification.h new file mode 100644 index 000000000000..57e7a7856360 --- /dev/null +++ b/notification.h @@ -0,0 +1,27 @@ +/** + * @file notification.h + * @brief Definitions for the notification framework. + * @note Copyright (C) 2014 Red Hat, Inc., Jiri Benc <jb...@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ +#ifndef HAVE_NOTIFICATION_H +#define HAVE_NOTIFICATION_H + +enum notification { + NOTIFY_DUMMY, +}; + +#endif diff --git a/tlv.c b/tlv.c index b8cdd3959c9b..430410f75397 100644 --- a/tlv.c +++ b/tlv.c @@ -242,6 +242,10 @@ static int mgt_post_recv(struct management_tlv *m, uint16_t data_len, pdsnp->neighborPropDelayThresh = ntohl(pdsnp->neighborPropDelayThresh); pdsnp->asCapable = ntohl(pdsnp->asCapable); break; + case SUBSCRIBE_EVENTS_NP: + if (data_len != sizeof(struct subscribe_events_np)) + goto bad_length; + break; case SAVE_IN_NON_VOLATILE_STORAGE: case RESET_NON_VOLATILE_STORAGE: case INITIALIZE: diff --git a/tlv.h b/tlv.h index 60c937db02ef..10ed301fdc04 100644 --- a/tlv.h +++ b/tlv.h @@ -79,6 +79,7 @@ enum management_action { #define PRIMARY_DOMAIN 0x4002 #define TIME_STATUS_NP 0xC000 #define GRANDMASTER_SETTINGS_NP 0xC001 +#define SUBSCRIBE_EVENTS_NP 0xC003 /* Port management ID values */ #define NULL_MANAGEMENT 0x0000 @@ -196,6 +197,13 @@ struct port_ds_np { Integer32 asCapable; } PACKED; + +#define EVENT_BITMASK_CNT 32 + +struct subscribe_events_np { + uint8_t bitmask[EVENT_BITMASK_CNT]; +} PACKED; + enum clock_type { CLOCK_TYPE_ORDINARY = 0x8000, CLOCK_TYPE_BOUNDARY = 0x4000, -- 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