]> git.ipfire.org Git - thirdparty/lldpd.git/blame - src/client/conf-med.c
lldpcli: possibility to configure tx-delay
[thirdparty/lldpd.git] / src / client / conf-med.c
CommitLineData
4b292b55
VB
1/* -*- mode: c; c-file-style: "openbsd" -*- */
2/*
3 * Copyright (c) 2012 Vincent Bernat <bernat@luffy.cx>
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <unistd.h>
19#include <string.h>
20
21#include "client.h"
22#include "../log.h"
23
9a775667
VB
24static int
25_cmd_medlocation(struct lldpctl_conn_t *conn,
26 struct cmd_env *env, int format)
4b292b55 27{
9a775667
VB
28 lldpctl_atom_t *iface;
29 while ((iface = cmd_iterate_on_interfaces(conn, env))) {
30 const char *name = lldpctl_atom_get_str(iface, lldpctl_k_interface_name);
31 lldpctl_atom_t *port = lldpctl_get_port(iface);
32 lldpctl_atom_t *med_location = NULL, *med_locations = NULL;
33 const char *what = NULL;
34 int ok = 0;
35
36 med_locations = lldpctl_atom_get(port, lldpctl_k_port_med_locations);
37 if (med_locations == NULL) {
38 log_warnx("lldpctl", "unable to set LLDP-MED location: support seems unavailable");
39 goto end;
40 }
41
42 med_location = lldpctl_atom_iter_value(med_locations,
43 lldpctl_atom_iter_next(med_locations,
44 lldpctl_atom_iter(med_locations)));
45
46 switch (format) {
47 case LLDP_MED_LOCFORMAT_COORD:
48 if ((what = "format", lldpctl_atom_set_int(med_location,
49 lldpctl_k_med_location_format,
50 format)) == NULL ||
51 (what = "latitude", lldpctl_atom_set_str(med_location,
52 lldpctl_k_med_location_latitude,
53 cmdenv_get(env, "latitude"))) == NULL ||
54 (what = "longitude", lldpctl_atom_set_str(med_location,
55 lldpctl_k_med_location_longitude,
56 cmdenv_get(env, "longitude"))) == NULL ||
57 (what = "altitude", lldpctl_atom_set_str(med_location,
58 lldpctl_k_med_location_altitude,
59 cmdenv_get(env, "altitude"))) == NULL ||
60 (what = "altitude unit", lldpctl_atom_set_str(med_location,
61 lldpctl_k_med_location_altitude_unit,
62 cmdenv_get(env, "altitude-unit"))) == NULL ||
63 (what = "datum", lldpctl_atom_set_str(med_location,
64 lldpctl_k_med_location_geoid,
65 cmdenv_get(env, "datum"))) == NULL)
66 log_warnx("lldpctl",
67 "unable to set LLDP MED location value for %s on %s. %s.",
68 what, name, lldpctl_last_strerror(conn));
69 else ok = 1;
70 break;
71 case LLDP_MED_LOCFORMAT_CIVIC:
72 if ((what = "format", lldpctl_atom_set_int(med_location,
73 lldpctl_k_med_location_format,
74 format)) == NULL ||
75 (what = "country", lldpctl_atom_set_str(med_location,
76 lldpctl_k_med_location_country,
77 cmdenv_get(env, "country"))) == NULL) {
78 log_warnx("lldpctl",
79 "unable to set LLDP MED location value for %s on %s. %s.",
80 what, name, lldpctl_last_strerror(conn));
81 break;
82 }
83 ok = 1;
84 for (lldpctl_map_t *addr_map =
85 lldpctl_key_get_map(lldpctl_k_med_civicaddress_type);
86 addr_map->string;
87 addr_map++) {
88 lldpctl_atom_t *cael, *caels;
89 const char *value = cmdenv_get(env, addr_map->string);
90 if (!value) continue;
91
92 caels = lldpctl_atom_get(med_location, lldpctl_k_med_location_ca_elements);
93 cael = lldpctl_atom_create(caels);
94
95 if (lldpctl_atom_set_str(cael, lldpctl_k_med_civicaddress_type,
96 addr_map->string) == NULL ||
97 lldpctl_atom_set_str(cael, lldpctl_k_med_civicaddress_value,
98 value) == NULL ||
99 lldpctl_atom_set(med_location,
100 lldpctl_k_med_location_ca_elements,
101 cael) == NULL) {
102 log_warnx("lldpctl",
103 "unable to add a civic address element `%s`. %s",
104 addr_map->string,
105 lldpctl_last_strerror(conn));
106 ok = 0;
107 }
108
109 lldpctl_atom_dec_ref(cael);
110 lldpctl_atom_dec_ref(caels);
111 if (!ok) break;
112 }
113 break;
114 case LLDP_MED_LOCFORMAT_ELIN:
115 if (lldpctl_atom_set_int(med_location,
116 lldpctl_k_med_location_format, format) == NULL ||
117 lldpctl_atom_set_str(med_location,
118 lldpctl_k_med_location_elin, cmdenv_get(env, "elin")) == NULL)
119 log_warnx("lldpctl", "unable to set LLDP MED location on %s. %s",
120 name, lldpctl_last_strerror(conn));
121 else ok = 1;
122 break;
123 }
124 if (ok) {
125 if (lldpctl_atom_set(port, lldpctl_k_port_med_locations,
126 med_location) == NULL) {
127 log_warnx("lldpctl", "unable to set LLDP MED location on %s. %s.",
128 name, lldpctl_last_strerror(conn));
129 } else
130 log_info("lldpctl", "LLDP-MED location has been set for port %s",
131 name);
132 }
133
134 end:
135 lldpctl_atom_dec_ref(med_location);
136 lldpctl_atom_dec_ref(med_locations);
137 lldpctl_atom_dec_ref(port);
4b292b55 138 }
9a775667
VB
139 return 1;
140}
4b292b55 141
9a775667
VB
142static int
143cmd_medlocation_coordinate(struct lldpctl_conn_t *conn, struct writer *w,
144 struct cmd_env *env, void *arg)
145{
146 log_debug("lldpctl", "set MED location coordinate");
147 return _cmd_medlocation(conn, env, LLDP_MED_LOCFORMAT_COORD);
148}
4b292b55 149
9a775667
VB
150static int
151cmd_medlocation_address(struct lldpctl_conn_t *conn, struct writer *w,
152 struct cmd_env *env, void *arg)
153{
154 log_debug("lldpctl", "set MED location address");
155 return _cmd_medlocation(conn, env, LLDP_MED_LOCFORMAT_CIVIC);
156}
157
158static int
159cmd_medlocation_elin(struct lldpctl_conn_t *conn, struct writer *w,
160 struct cmd_env *env, void *arg)
161{
162 log_debug("lldpctl", "set MED location ELIN");
163 return _cmd_medlocation(conn, env, LLDP_MED_LOCFORMAT_ELIN);
164}
165
166static int
167cmd_medpolicy(struct lldpctl_conn_t *conn, struct writer *w,
168 struct cmd_env *env, void *arg)
169{
170 log_debug("lldpctl", "set MED policy");
171 lldpctl_atom_t *iface;
172 while ((iface = cmd_iterate_on_interfaces(conn, env))) {
173 const char *name = lldpctl_atom_get_str(iface, lldpctl_k_interface_name);
174 lldpctl_atom_t *port = lldpctl_get_port(iface);
175 lldpctl_atom_t *med_policy = NULL, *med_policies = NULL;
176 const char *what = NULL;
177
178 med_policies = lldpctl_atom_get(port, lldpctl_k_port_med_policies);
179 if (med_policies == NULL) {
180 log_warnx("lldpctl", "unable to set LLDP-MED policies: support seems unavailable");
181 goto end;
182 }
183
184 med_policy = lldpctl_atom_iter_value(med_policies,
185 lldpctl_atom_iter_next(med_policies,
186 lldpctl_atom_iter(med_policies)));
187
188 if ((what = "application", lldpctl_atom_set_str(med_policy,
189 lldpctl_k_med_policy_type,
190 cmdenv_get(env, "application"))) == NULL ||
191 (what = "unknown flag", lldpctl_atom_set_int(med_policy,
192 lldpctl_k_med_policy_unknown,
193 cmdenv_get(env, "unknown")?1:0)) == NULL ||
194 (what = "vlan",
195 cmdenv_get(env, "vlan")?
196 lldpctl_atom_set_str(med_policy,
197 lldpctl_k_med_policy_vid,
198 cmdenv_get(env, "vlan")):
199 lldpctl_atom_set_int(med_policy,
200 lldpctl_k_med_policy_vid, 0)) == NULL ||
201 (what = "priority",
202 cmdenv_get(env, "priority")?
203 lldpctl_atom_set_str(med_policy,
204 lldpctl_k_med_policy_priority,
205 cmdenv_get(env, "priority")):
206 lldpctl_atom_set_int(med_policy,
207 lldpctl_k_med_policy_priority,
208 0)) == NULL ||
209 (what = "dscp",
210 cmdenv_get(env, "dscp")?
211 lldpctl_atom_set_str(med_policy,
212 lldpctl_k_med_policy_dscp,
213 cmdenv_get(env, "dscp")):
214 lldpctl_atom_set_int(med_policy,
215 lldpctl_k_med_policy_dscp,
216 0)) == NULL)
217 log_warnx("lldpctl",
218 "unable to set LLDP MED policy value for %s on %s. %s.",
219 what, name, lldpctl_last_strerror(conn));
220 else {
221 if (lldpctl_atom_set(port, lldpctl_k_port_med_policies,
222 med_policy) == NULL) {
223 log_warnx("lldpctl", "unable to set LLDP MED policy on %s. %s.",
224 name, lldpctl_last_strerror(conn));
225 } else
226 log_info("lldpctl", "LLDP-MED policy has been set for port %s",
227 name);
228 }
229
230 end:
231 lldpctl_atom_dec_ref(med_policy);
232 lldpctl_atom_dec_ref(med_policies);
233 lldpctl_atom_dec_ref(port);
4b292b55 234 }
9a775667 235 return 1;
4b292b55
VB
236}
237
9a775667
VB
238/**
239 * Register `configure med location coordinate` commands.
240 */
241static void
242register_commands_medloc_coord(struct cmd_node *configure_medlocation)
243{
244 /* MED location coordinate (set) */
245 struct cmd_node *configure_medloc_coord = commands_new(
246 configure_medlocation,
247 "coordinate", "MED location coordinate configuration",
248 NULL, NULL, NULL);
249 commands_new(configure_medloc_coord,
250 NEWLINE, "Configure MED location coordinates",
251 cmd_check_env, cmd_medlocation_coordinate,
252 "latitude,longitude,altitude,altitude-unit,datum");
253 commands_new(
254 commands_new(
255 configure_medloc_coord,
256 "latitude", "Specify latitude",
257 cmd_check_no_env, NULL, "latitude"),
258 NULL, "Latitude as xx.yyyyN or xx.yyyyS",
259 NULL, cmd_store_env_value_and_pop2, "latitude");
260 commands_new(
261 commands_new(
262 configure_medloc_coord,
263 "longitude", "Specify longitude",
264 cmd_check_no_env, NULL, "longitude"),
265 NULL, "Longitude as xx.yyyyE or xx.yyyyW",
266 NULL, cmd_store_env_value_and_pop2, "longitude");
267 struct cmd_node *altitude = commands_new(
268 commands_new(
269 configure_medloc_coord,
270 "altitude", "Specify altitude",
271 cmd_check_no_env, NULL, "altitude"),
272 NULL, "Altitude",
273 NULL, cmd_store_env_value, "altitude");
274 commands_new(altitude,
275 "m", "meters",
276 NULL, cmd_store_env_value_and_pop3, "altitude-unit");
277 commands_new(altitude,
278 "f", "floors",
279 NULL, cmd_store_env_value_and_pop3, "altitude-unit");
280
281 struct cmd_node *datum = commands_new(configure_medloc_coord,
282 "datum", "Specify datum",
283 cmd_check_no_env, NULL, "datum");
284 for (lldpctl_map_t *datum_map =
285 lldpctl_key_get_map(lldpctl_k_med_location_geoid);
286 datum_map->string;
287 datum_map++)
288 commands_new(datum, datum_map->string, NULL,
289 NULL, cmd_store_env_value_and_pop2, "datum");
4b292b55
VB
290}
291
292/**
9a775667 293 * Register `configure med location address` commands.
4b292b55 294 */
9a775667
VB
295static void
296register_commands_medloc_addr(struct cmd_node *configure_medlocation)
4b292b55 297{
9a775667
VB
298 /* MED location address (set) */
299 struct cmd_node *configure_medloc_addr = commands_new(
300 configure_medlocation,
301 "address", "MED location address configuration",
302 NULL, NULL, NULL);
303 commands_new(configure_medloc_addr,
304 NEWLINE, "Configure MED location address",
305 cmd_check_env, cmd_medlocation_address,
306 "country");
4b292b55 307
9a775667
VB
308 /* Country */
309 commands_new(
310 commands_new(
311 configure_medloc_addr,
312 "country", "Specify country (mandatory)",
313 cmd_check_no_env, NULL, "country"),
314 NULL, "Country as a two-letter code",
315 NULL, cmd_store_env_value_and_pop2, "country");
316
317 /* Other fields */
318 for (lldpctl_map_t *addr_map =
319 lldpctl_key_get_map(lldpctl_k_med_civicaddress_type);
320 addr_map->string;
321 addr_map++)
322 commands_new(
323 commands_new(
324 configure_medloc_addr,
325 strdup(totag(addr_map->string)), /* TODO: memory leak, happens once */
326 addr_map->string,
327 cmd_check_no_env, NULL, addr_map->string),
328 NULL, addr_map->string,
329 NULL, cmd_store_env_value_and_pop2, addr_map->string);
4b292b55
VB
330}
331
332/**
9a775667 333 * Register `configure med location elin` commands.
4b292b55 334 */
9a775667
VB
335static void
336register_commands_medloc_elin(struct cmd_node *configure_medlocation)
337{
338 /* MED location elin (set) */
339 commands_new(
340 commands_new(
341 commands_new(
342 configure_medlocation,
343 "elin", "MED location ELIN configuration",
344 NULL, NULL, NULL),
345 NULL, "ELIN number",
346 NULL, cmd_store_env_value, "elin"),
347 NEWLINE, "Set MED location ELIN number",
348 NULL, cmd_medlocation_elin, NULL);
349}
350
351/**
352 * Register `configure med location` commands.
353 */
354static void
0a138003 355register_commands_medloc(struct cmd_node *configure_med)
9a775667
VB
356{
357 struct cmd_node *configure_medlocation = commands_new(
358 configure_med,
359 "location", "MED location configuration",
360 NULL, NULL, NULL);
361
362 register_commands_medloc_coord(configure_medlocation);
363 register_commands_medloc_addr(configure_medlocation);
364 register_commands_medloc_elin(configure_medlocation);
9a775667
VB
365}
366
4b292b55 367static int
9a775667 368cmd_check_application_but_no(struct cmd_env *env, void *arg)
4b292b55 369{
9a775667
VB
370 const char *what = arg;
371 if (!cmdenv_get(env, "application")) return 0;
372 if (cmdenv_get(env, what)) return 0;
373 return 1;
374}
375static int
9a775667
VB
376cmd_store_app_env_value_and_pop2(struct lldpctl_conn_t *conn, struct writer *w,
377 struct cmd_env *env, void *value)
378{
379 return cmd_store_something_env_value_and_pop2("application", env, value);
380}
381static int
9a775667
VB
382cmd_store_prio_env_value_and_pop2(struct lldpctl_conn_t *conn, struct writer *w,
383 struct cmd_env *env, void *value)
384{
385 return cmd_store_something_env_value_and_pop2("priority", env, value);
386}
4b292b55 387
9a775667
VB
388/**
389 * Register `configure med policy` commands.
390 */
391static void
0a138003 392register_commands_medpol(struct cmd_node *configure_med)
9a775667
VB
393{
394 struct cmd_node *configure_medpolicy = commands_new(
395 configure_med,
396 "policy", "MED policy configuration",
397 NULL, NULL, NULL);
398
9a775667
VB
399 commands_new(
400 configure_medpolicy,
401 NEWLINE, "Apply new MED policy",
402 cmd_check_env, cmd_medpolicy, "application");
403
404 /* Application */
405 struct cmd_node *configure_application =
406 commands_new(
407 configure_medpolicy,
408 "application", "MED policy application",
409 cmd_check_no_env, NULL, "application");
410
411 for (lldpctl_map_t *pol_map =
412 lldpctl_key_get_map(lldpctl_k_med_policy_type);
413 pol_map->string;
414 pol_map++) {
415 char *tag = strdup(totag(pol_map->string)); /* TODO: memory leak, happens once */
9a775667
VB
416 commands_new(
417 configure_application,
418 tag,
419 pol_map->string,
420 NULL, cmd_store_app_env_value_and_pop2, pol_map->string);
421 }
422
423 /* Remaining keywords */
424 commands_new(
425 configure_medpolicy,
426 "unknown", "Set unknown flag",
427 cmd_check_application_but_no, cmd_store_env_and_pop, "unknown");
428 commands_new(
429 commands_new(
430 configure_medpolicy,
431 "vlan", "VLAN advertising",
432 cmd_check_application_but_no, NULL, "vlan"),
433 NULL, "VLAN ID to advertise",
434 NULL, cmd_store_env_value_and_pop2, "vlan");
435 commands_new(
436 commands_new(
437 configure_medpolicy,
438 "dscp", "DiffServ advertising",
439 cmd_check_application_but_no, NULL, "dscp"),
440 NULL, "DSCP value to advertise (between 0 and 63)",
441 NULL, cmd_store_env_value_and_pop2, "dscp");
442 struct cmd_node *priority =
443 commands_new(
444 configure_medpolicy,
445 "priority", "MED policy priority",
446 cmd_check_application_but_no, NULL, "priority");
447 for (lldpctl_map_t *prio_map =
448 lldpctl_key_get_map(lldpctl_k_med_policy_priority);
449 prio_map->string;
450 prio_map++) {
451 char *tag = strdup(totag(prio_map->string)); /* TODO: memory leak, happens once */
452 commands_new(
453 priority,
454 tag, prio_map->string,
455 NULL, cmd_store_prio_env_value_and_pop2, prio_map->string);
4b292b55 456 }
9a775667 457}
4b292b55 458
9a775667 459/**
e15f96d2 460 * Register "configure med *"
9a775667
VB
461 */
462void
e15f96d2 463register_commands_configure_med(struct cmd_node *configure)
9a775667 464{
f88442ac
VB
465 if (lldpctl_key_get_map(
466 lldpctl_k_med_policy_type)[0].string == NULL)
467 return;
468
e15f96d2
VB
469 struct cmd_node *configure_med = commands_new(
470 configure,
471 "med", "MED configuration",
9a775667 472 NULL, NULL, NULL);
9a775667 473
e15f96d2
VB
474 register_commands_medloc(configure_med);
475 register_commands_medpol(configure_med);
476 register_commands_medpow(configure_med);
4b292b55 477}