My Project
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros
dfg_writer.c
Go to the documentation of this file.
1 /*
2 START OF LICENSE STUB
3  DeDOS: Declarative Dispersion-Oriented Software
4  Copyright (C) 2017 University of Pennsylvania, Georgetown University
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 END OF LICENSE STUB
19 */
20 #include <string.h>
21 #include <stdlib.h>
22 #include "runtime_communication.h"
23 #include "controller_stats.h"
24 #include "timeseries.h"
25 #include "dfg.h"
26 #include "controller_dfg.h"
27 #include "jsmn.h"
28 #include "logging.h"
29 
30 #include <unistd.h>
31 
32 #define JSON_LEN_INCREMENT 1024
33 
34 #define CHECK_JSON_LEN(json, len)\
35  while ( (int)((json).allocated_size - (json).length) < (len)) { \
36  log(LOG_DFG_WRITER, "Reallocating to %d", (int)(json.allocated_size + JSON_LEN_INCREMENT)); \
37  (json).string = realloc((json).string, (json).allocated_size + JSON_LEN_INCREMENT); \
38  (json).allocated_size += JSON_LEN_INCREMENT; \
39  }
40 
41 #define START_JSON(json) \
42  (json).length = 0
43 
44 #define START_LIST(json) \
45  do { \
46  CHECK_JSON_LEN(json, 2); \
47  (json).length += sprintf((json).string + (json).length, "[ "); \
48  } while (0)
49 
50 
51 // This is a hacky trick. Steps back by one to overwrite the previous comma
52 // If list/obj is empty, it will overwrite the space at the start of the list/obj
53 #define END_LIST(json) \
54  do { \
55  CHECK_JSON_LEN(json, 2); \
56  (json).length += sprintf((json).string + (json).length - 1, "],") - 1; \
57  } while (0)
58 
59 #define START_OBJ(json)\
60  do { \
61  CHECK_JSON_LEN(json, 2); \
62  (json).length += sprintf((json).string + (json).length, "{ " ); \
63  } while (0)
64 
65 #define END_OBJ(json) \
66  do { \
67  CHECK_JSON_LEN(json, 2); \
68  (json).length += sprintf((json).string + (json).length - 1 , "},") - 1; \
69  } while (0)
70 
71 #define KEY_VAL(json, key, fmt, value, value_len) \
72  do { \
73  CHECK_JSON_LEN(json, value_len + strlen(key) + 8); \
74  (json).length += sprintf((json).string + (json).length, "\"" key "\":" fmt ",", value); \
75  } while (0)
76 
77 #define KEY_INTVAL(json, key, value) \
78  KEY_VAL(json, key, "%d", value, 128)
79 
80 #define KEY_STRVAL(json, key, value) \
81  KEY_VAL(json, key, "\"%s\"", value, strlen(value))
82 
83 #define FMT_KEY_VAL(json, key_fmt, key, key_len, val_fmt, value, value_len) \
84  do { \
85  CHECK_JSON_LEN(json, key_len + value_len + 8); \
86  (json).length += sprintf((json).string + (json).length, "\"" key_fmt "\":\"" val_fmt "\",", key, value); \
87  } while (0)
88 
89 #define KEY(json, key)\
90  do { \
91  CHECK_JSON_LEN(json, strlen(key) + 4); \
92  (json).length += sprintf((json).string + (json).length, "\"" key "\":"); \
93  } while (0)
94 
95 #define VALUE(json, fmt, value, value_len) \
96  do { \
97  CHECK_JSON_LEN(json, value_len + 4); \
98  (json).length += sprintf((json).string + (json).length, fmt ",", value); \
99  } while (0)
100 
101 #define END_JSON(json) \
102  (json).string[(json).length-1] = '\0'
103 
104 struct json_output {
105  char *string;
107  int list_cnt;
108  int length;
109 };
110 
111 
112 static char *stat_to_json(struct timed_rrdb *timeseries, int n_stats) {
113  static struct json_output json;
114 
115  int write_index = timeseries->write_index;
116  START_JSON(json);
117  START_LIST(json);
118 
119  for (int i= write_index - n_stats - 1; i<write_index; i++) {
120  int index = i >= 0 ? i : RRDB_ENTRIES + i;
121  if (timeseries->time[index].tv_sec == 0 && timeseries->time[index].tv_nsec == 0) {
122  continue;
123  }
124  START_OBJ(json);
125  char ts[32];
126  sprintf(ts, "%ld.%09ld", timeseries->time[index].tv_sec,
127  timeseries->time[index].tv_nsec);
128  KEY_VAL(json, "time", "%s", ts, 32);
129  KEY_VAL(json, "value", "%.3f", timeseries->data[index], 16);
130  END_OBJ(json);
131  }
132  END_LIST(json);
133  END_JSON(json);
134  return json.string;
135 }
136 
137 
138 static char *meta_routing_to_json(struct dfg_meta_routing *meta_routing) {
139  static struct json_output json;
140 
141  START_JSON(json);
142  START_OBJ(json);
143 
144  KEY(json, "src_types");
145  START_LIST(json);
146  for (int i=0; i<meta_routing->n_src_types; i++) {
147  VALUE(json, "%d", meta_routing->src_types[i]->id, 8);
148  }
149  END_LIST(json);
150 
151  KEY(json, "dst_types");
152  START_LIST(json);
153  for (int i=0; i<meta_routing->n_dst_types; i++) {
154  VALUE(json, "%d", meta_routing->dst_types[i]->id, 8);
155  }
156  END_LIST(json);
157 
158  END_OBJ(json);
159  END_JSON(json);
160  return json.string;
161 }
162 
163 static char *dependency_to_json(struct dfg_dependency *dep) {
164  static struct json_output json;
165 
166  START_JSON(json);
167  START_OBJ(json);
168  KEY_INTVAL(json, "type", dep->type->id);
169  KEY_STRVAL(json, "locality", dep->locality == MSU_IS_LOCAL ? "local" : "remote");
170  END_OBJ(json);
171  END_JSON(json);
172 
173  return json.string;
174 }
175 
176 static char *msu_type_to_json(struct dfg_msu_type *type) {
177  static struct json_output json;
178 
179  START_JSON(json);
180  START_OBJ(json);
181 
182  KEY_INTVAL(json, "id", type->id);
183  KEY_STRVAL(json, "name", type->name);
184 
185  char *meta_routing = meta_routing_to_json(&type->meta_routing);
186  KEY(json, "meta_routing");
187  VALUE(json, "%s", meta_routing, strlen(meta_routing));
188 
189  KEY(json, "dependencies");
190  START_LIST(json);
191  for (int i=0; i<type->n_dependencies; i++) {
192  char *dependency = dependency_to_json(type->dependencies[i]);
193  VALUE(json, "%s", dependency, strlen(dependency));
194  }
195  END_LIST(json);
196 
197  KEY_INTVAL(json, "cloneable", type->cloneable);
198  KEY_INTVAL(json, "colocation_group", type->colocation_group);
199 
200  END_OBJ(json);
201  END_JSON(json);
202  return json.string;
203 }
204 
205 static char *scheduling_to_json(struct dfg_scheduling *sched) {
206  static struct json_output json;
207 
208  START_JSON(json);
209  START_OBJ(json);
210 
211  KEY_INTVAL(json, "runtime", sched->runtime->id);
212  KEY_INTVAL(json, "thread_id", sched->thread->id);
213 
214  KEY(json, "routes");
215  START_LIST(json);
216  for (int i=0; i<sched->n_routes; i++) {
217  VALUE(json, "%d", sched->routes[i]->id, 8);
218  }
219  END_LIST(json);
220 
221  END_OBJ(json);
222  END_JSON(json);
223 
224  return json.string;
225 }
226 
227 static char *msu_stats_to_json(int msu_id, int n_stats) {
228  static struct json_output json;
229 
230  START_JSON(json);
231  START_LIST(json);
232 
233  for (int i=0; i<N_REPORTED_MSU_STAT_TYPES; i++) {
234  START_OBJ(json);
235  KEY_STRVAL(json, "label", reported_msu_stat_types[i].name);
236  KEY(json, "stats");
237  struct timed_rrdb *stat = get_msu_stat(reported_msu_stat_types[i].id, msu_id);
238  if (stat == NULL) {
239  log_error("Cannot get MSU stat %d (idx %d) msu %d",
240  reported_msu_stat_types[i].id, i, msu_id);
241  return "";
242  }
243  char *stat_json = stat_to_json(stat, n_stats);
244  VALUE(json, "%s", stat_json, strlen(stat_json));
245  END_OBJ(json);
246  }
247  END_LIST(json);
248  END_JSON(json);
249 
250  return json.string;
251 }
252 
253 
254 static char *msu_to_json(struct dfg_msu *msu, int n_stats) {
255  static struct json_output json;
256 
257  START_JSON(json);
258  START_OBJ(json);
259 
260  KEY_INTVAL(json, "id", msu->id);
262  KEY_STRVAL(json, "vertex_type", "entry/exit");
263  } else if (msu->vertex_type & ENTRY_VERTEX_TYPE) {
264  KEY_STRVAL(json, "vertex_type", "entry");
265  } else if (msu->vertex_type & EXIT_VERTEX_TYPE) {
266  KEY_STRVAL(json, "vertex_type", "exit");
267  } else {
268  KEY_STRVAL(json, "vertex_type", "nop");
269  }
270 
271  KEY_STRVAL(json, "init_data", msu->init_data.init_data);
272  KEY_INTVAL(json, "type", msu->type->id);
273  KEY_STRVAL(json, "blocking_mode",
274  msu->blocking_mode == BLOCKING_MSU ? "blocking" : "non-blocking");
275 
276  char *scheduling = scheduling_to_json(&msu->scheduling);
277  KEY_VAL(json, "scheduling", "%s", scheduling, strlen(scheduling));
278 
279  if (n_stats > 0) {
280  char *stats = msu_stats_to_json(msu->id, n_stats);
281  KEY_VAL(json, "stats", "%s", stats, strlen(stats));
282  }
283 
284 
285  END_OBJ(json);
286  END_JSON(json);
287  return json.string;
288 }
289 
290 static char *endpoint_to_json(struct dfg_route_endpoint *ep) {
291  static struct json_output json;
292  START_JSON(json);
293  START_OBJ(json);
294 
295  KEY_INTVAL(json, "key", ep->key);
296  KEY_INTVAL(json, "msu", ep->msu->id);
297 
298  END_OBJ(json);
299  END_JSON(json);
300  return json.string;
301 }
302 
303 static char *route_to_json(struct dfg_route *route) {
304  static struct json_output json;
305 
306  START_JSON(json);
307  START_OBJ(json);
308 
309  KEY_INTVAL(json, "id", route->id);
310  KEY_INTVAL(json, "type", route->msu_type->id);
311 
312  KEY(json, "endpoints");
313  START_LIST(json);
314  for (int i=0; i<route->n_endpoints; i++) {
315  char *ep = endpoint_to_json(route->endpoints[i]);
316  VALUE(json, "%s", ep, strlen(ep));
317  }
318  END_LIST(json);
319  END_OBJ(json);
320  END_JSON(json);
321 
322  return json.string;
323 }
324 
325 
326 static char *runtime_to_json(struct dfg_runtime *rt) {
327  static struct json_output json;
328 
329  START_JSON(json);
330  START_OBJ(json);
331 
332  KEY_INTVAL(json, "id", rt->id);
333  char ip[32];
334  struct in_addr addr = {rt->ip};
335  inet_ntop(AF_INET, &addr, ip, 32);
336  KEY_STRVAL(json, "ip", ip);
337 
338  KEY_INTVAL(json, "port", rt->port);
339  KEY_INTVAL(json, "n_cores", rt->n_cores);
340 
341  KEY_INTVAL(json, "n_pinned_threads", rt->n_pinned_threads);
342  KEY_INTVAL(json, "n_unpinned_threads", rt->n_unpinned_threads);
343 
344  KEY_INTVAL(json, "connected", runtime_fd(rt->id) > 0 ? 1 : 0);
345 
346  KEY(json, "routes");
347  START_LIST(json);
348  for (int i=0; i<rt->n_routes; i++) {
349  char *route = route_to_json(rt->routes[i]);
350  VALUE(json, "%s", route, strlen(route));
351  }
352  END_LIST(json);
353  END_OBJ(json);
354  END_JSON(json);
355 
356  return json.string;
357 }
358 
359 static pthread_mutex_t json_lock;
360 static int initialized = 0;
361 
362 char *dfg_to_json(struct dedos_dfg *dfg, int n_stats) {
363  static struct json_output json;
364  if (!initialized) {
365  pthread_mutex_init(&json_lock, NULL);
366  initialized = 1;
367  }
368  pthread_mutex_lock(&json_lock);
369 
370  START_JSON(json);
371  START_OBJ(json);
372 
373  KEY_STRVAL(json, "application_name", dfg->application_name);
374  char ip[32];
375  struct in_addr addr = {htons(dfg->global_ctl_ip)};
376  inet_ntop(AF_INET, &addr, ip, 32);
377  log(LOG_TEST, "IP IS %s", ip);
378  KEY_STRVAL(json, "global_ctl_ip", ip);
379 
380  KEY_INTVAL(json, "global_ctl_port", dfg->global_ctl_port);
381 
382  KEY(json, "MSU_types");
383  START_LIST(json);
384  for (int i=0; i<dfg->n_msu_types; i++) {
385  char *type = msu_type_to_json(dfg->msu_types[i]);
386  VALUE(json, "%s", type, strlen(type));
387  }
388  END_LIST(json);
389 
390  KEY(json, "MSUs");
391  START_LIST(json);
392  for (int i=0; i<dfg->n_msus; i++) {
393  char *msu = msu_to_json(dfg->msus[i], n_stats);
394  VALUE(json, "%s", msu, strlen(msu));
395  }
396  END_LIST(json);
397 
398  KEY(json, "runtimes");
399  START_LIST(json);
400  for (int i=0; i<dfg->n_runtimes; i++) {
401  char *rt = runtime_to_json(dfg->runtimes[i]);
402  VALUE(json, "%s", rt, strlen(rt));
403  }
404  END_LIST(json);
405 
406  END_OBJ(json);
407  END_JSON(json);
408 
409  pthread_mutex_unlock(&json_lock);
410  return json.string;
411 }
412 
413 void dfg_to_file(char *filename) {
414  lock_dfg();
415  struct dedos_dfg *dfg = get_dfg();
416  char *dfg_json = dfg_to_json(dfg, STAT_SAMPLE_SIZE);
417  unlock_dfg();
418  int json_size = strlen(dfg_json);
419  FILE *file = fopen(filename, "w");
420  if (file == NULL) {
421  log_perror("Cannot write DFG to %s", filename);
422  return;
423  }
424  fwrite(dfg_json, sizeof(char), json_size, file);
425  fwrite("\n", sizeof(char), 1, file);
426  fclose(file);
427 }
428 
429 int dfg_to_fd(int fd) {
430  struct dedos_dfg *dfg = get_dfg();
431  char *dfg_json = dfg_to_json(dfg, STAT_SAMPLE_SIZE);
432  unlock_dfg();
433 
434  size_t json_size = strlen(dfg_json);
435 
436  size_t written = 0;
437  while (written < json_size) {
438  ssize_t rtn = write(fd, dfg_json + written, json_size - written);
439  if (rtn < 0) {
440  log_error("error writing dfg to fd %d", fd);
441  return -1;
442  }
443  written += rtn;
444  }
445  return 0;
446 }
static char * msu_stats_to_json(int msu_id, int n_stats)
Definition: dfg_writer.c:227
#define START_JSON(json)
Definition: dfg_writer.c:41
#define KEY_INTVAL(json, key, value)
Definition: dfg_writer.c:77
int n_routes
The routes that an MSU can send to.
Definition: dfg.h:120
MSUs which must be present for another MSU to be cloned.
Definition: dfg.h:203
#define EXIT_VERTEX_TYPE
Bitmask representing an MSU through which messages exit DeDOS.
Definition: dfg.h:211
int n_msus
The number of MSUs in dedos_dfg::msus.
Definition: dfg.h:255
uint32_t ip
IP of the node on which the runtime is running.
Definition: dfg.h:75
Round-robin database (circular buffer) for storing timeseries data.
Definition: timeseries.h:36
static char * stat_to_json(struct timed_rrdb *timeseries, int n_stats)
Definition: dfg_writer.c:112
struct dfg_msu_type * type
The MSU type which must be present.
Definition: dfg.h:204
int lock_dfg()
static char * scheduling_to_json(struct dfg_scheduling *sched)
Definition: dfg_writer.c:205
int global_ctl_port
Port of the global controller.
Definition: dfg.h:242
#define KEY(json, key)
Definition: dfg_writer.c:89
struct dfg_scheduling scheduling
Information about where an MSU is scheduled.
Definition: dfg.h:225
struct dfg_route * routes[64]
Routes located on this runtime.
Definition: dfg.h:83
uint32_t global_ctl_ip
IP address of the global controller.
Definition: dfg.h:241
int n_cores
Number of cores on the runtime node.
Definition: dfg.h:77
double data[240]
The statistics.
Definition: timeseries.h:37
static char * dependency_to_json(struct dfg_dependency *dep)
Definition: dfg_writer.c:163
size_t allocated_size
Definition: dfg_writer.c:106
#define VALUE(json, fmt, value, value_len)
Definition: dfg_writer.c:95
uint8_t vertex_type
Whether the MSU is #ENTRY, #EXIT, or possible #ENTRY | #EXIT.
Definition: dfg.h:218
static struct stat_type_label reported_msu_stat_types[]
Definition: stats.h:111
int n_src_types
The number of types that should route to this MSU.
Definition: dfg.h:131
int n_msu_types
The number of elements in dedos_dfg::msu_types.
Definition: dfg.h:250
static int route(struct msu_type *type, struct local_msu *sender, struct msu_msg *msg, struct msu_endpoint *output)
Definition: baremetal_msu.c:30
int n_dst_types
The number of types that this msu should route to.
Definition: dfg.h:133
static char * msu_type_to_json(struct dfg_msu_type *type)
Definition: dfg_writer.c:176
#define ENTRY_VERTEX_TYPE
Bitmask representing an MSU through which messages enter DeDOS.
Definition: dfg.h:209
char name[32]
A name describing the function of the MSU.
Definition: dfg.h:179
#define log_perror(fmt,...)
Definition: logging.h:102
int id
Unique identifier for the runtime.
Definition: dfg.h:74
Logging of status messages to the terminal.
struct timed_rrdb * get_msu_stat(enum stat_id id, unsigned int msu_id)
int colocation_group
Definition: dfg.h:191
struct dfg_msu_type * type
The type of the MSU and meta-routing information.
Definition: dfg.h:221
int write_index
Offset into the rrdb at which writing has occurred.
Definition: timeseries.h:39
char * string
Definition: dfg_writer.c:105
static char * route_to_json(struct dfg_route *route)
Definition: dfg_writer.c:303
char application_name[64]
Description of the whole application.
Definition: dfg.h:240
char * dfg_to_json(struct dedos_dfg *dfg, int n_stats)
Definition: dfg_writer.c:362
Representation of a runtime in the DFG.
Definition: dfg.h:73
static pthread_mutex_t json_lock
Definition: dfg_writer.c:359
struct dfg_dependency * dependencies[32]
These MSU types must be present in order for this MSU type to be cloned.
Definition: dfg.h:183
struct dfg_route_endpoint * endpoints[256]
The endpoints of the route.
Definition: dfg.h:156
int n_endpoints
The number of endpoints in dfg_route::endpoints.
Definition: dfg.h:157
const char * name
Definition: http_parser.c:485
struct dfg_runtime * runtime
The runtime on which an MSU is running.
Definition: dfg.h:117
#define END_LIST(json)
Definition: dfg_writer.c:53
int unlock_dfg()
int n_runtimes
The number of elements in dedos_dfg::runtimes.
Definition: dfg.h:260
static char * msu_to_json(struct dfg_msu *msu, int n_stats)
Definition: dfg_writer.c:254
#define N_REPORTED_MSU_STAT_TYPES
Definition: stats.h:114
static char * runtime_to_json(struct dfg_runtime *rt)
Definition: dfg_writer.c:326
#define log_error(fmt,...)
Definition: logging.h:101
static char * meta_routing_to_json(struct dfg_meta_routing *meta_routing)
Definition: dfg_writer.c:138
#define KEY_VAL(json, key, fmt, value, value_len)
Definition: dfg_writer.c:71
struct dfg_msu * msu
The MSU at this endpoint to which a message would be delivered.
Definition: dfg.h:143
struct dfg_msu_type * src_types[512]
The types that should route to this MSU.
Definition: dfg.h:130
A type of MSU.
Definition: dfg.h:176
#define START_LIST(json)
Definition: dfg_writer.c:44
struct dfg_msu_type * msu_types[32]
MSU types which may be present in the application.
Definition: dfg.h:248
int dfg_to_fd(int fd)
Definition: dfg_writer.c:429
int id
A unique identifier for the MSU.
Definition: dfg.h:217
int cloneable
If cloneable == N, this MSU can be cloned on runtimes numbered up to and including N...
Definition: dfg.h:189
static char * endpoint_to_json(struct dfg_route_endpoint *ep)
Definition: dfg_writer.c:290
int n_unpinned_threads
Number of the above-threads which are unpinned.
Definition: dfg.h:81
Describes which MSU types a given MSU type should route to if it is cloned.
Definition: dfg.h:129
#define RRDB_ENTRIES
timeseries.h
Definition: timeseries.h:32
struct dfg_thread * thread
The thread on which an MSU is running.
Definition: dfg.h:118
int id
Unique identifier for the thread.
Definition: dfg.h:105
Representation of a single MSU in the dfg.
Definition: dfg.h:216
#define START_OBJ(json)
Definition: dfg_writer.c:59
void dfg_to_file(char *filename)
Definition: dfg_writer.c:413
#define STAT_SAMPLE_SIZE
Number of statistics sampled in each send from runtime to controller.
Definition: stats.h:129
struct dfg_msu_type * dst_types[512]
The types that this msu should route to.
Definition: dfg.h:132
int n_pinned_threads
Number of the above-threads which are pinned.
Definition: dfg.h:80
int id
A unique identifier for the MSU type.
Definition: dfg.h:177
int runtime_fd(unsigned int runtime_id)
int id
A unique identifier for the route.
Definition: dfg.h:153
enum msu_locality locality
Whether it must be present on the same machine.
Definition: dfg.h:205
struct dfg_route * routes[32]
Definition: dfg.h:119
Top-level structure holding the data-flow graph.
Definition: dfg.h:239
A route through which MSU messages can be passed.
Definition: dfg.h:152
static struct dedos_dfg * dfg
Static local copy of the DFG, so each call doesn't have to pass a copy.
Definition: dfg.c:32
struct msu_init_data init_data
Initial data passed to the MSU.
Definition: dfg.h:219
Interfaces for the creation and modification of the data-flow-graph and and general description of th...
struct dfg_runtime * runtimes[16]
The runtimes present in the application.
Definition: dfg.h:258
A single endpoint for an MSU route.
Definition: dfg.h:139
uint32_t key
The key associated with this endpoint.
Definition: dfg.h:140
Structure representing the scheduling of an MSU on a runtime.
Definition: dfg.h:116
struct timespec time[240]
The time at which the stats were gathered.
Definition: timeseries.h:38
int n_routes
Number of routes above.
Definition: dfg.h:84
char init_data[64]
Definition: dfg.h:67
#define log(level, fmt,...)
Log at a custom level.
Definition: logging.h:147
struct dedos_dfg * get_dfg()
Definition: runtime_dfg.c:115
int n_dependencies
The number of elements in dfg_msu_type::dependencies.
Definition: dfg.h:184
#define END_OBJ(json)
Definition: dfg_writer.c:65
int port
Port on which the runtime is listening for controller/inter-runtime.
Definition: dfg.h:76
struct dfg_meta_routing meta_routing
Which types of msus route to/from this MSU.
Definition: dfg.h:180
static int initialized
Definition: dfg_writer.c:360
#define KEY_STRVAL(json, key, value)
Definition: dfg_writer.c:80
#define END_JSON(json)
Definition: dfg_writer.c:101
enum blocking_mode blocking_mode
Whether the MSU is blocking or not.
Definition: dfg.h:223
struct dfg_msu_type * msu_type
The type of MSU to which this route delivers.
Definition: dfg.h:155
struct dfg_msu * msus[512]
The MSUs present in the application.
Definition: dfg.h:253