iproute2/ip/ipioam6.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * ioam6.c "ip ioam"
   4 *
   5 * Author: Justin Iurman <justin.iurman@uliege.be>
   6 */
   7
   8#include <stdio.h>
   9#include <stdlib.h>
  10#include <string.h>
  11#include <unistd.h>
  12#include <errno.h>
  13#include <inttypes.h>
  14
  15#include <linux/genetlink.h>
  16#include <linux/ioam6_genl.h>
  17
  18#include "utils.h"
  19#include "ip_common.h"
  20#include "libgenl.h"
  21#include "json_print.h"
  22
  23static void usage(void)
  24{
  25        fprintf(stderr,
  26                "Usage: ip ioam { COMMAND | help }\n"
  27                "       ip ioam namespace show\n"
  28                "       ip ioam namespace add ID [ data DATA32 ] [ wide DATA64 ]\n"
  29                "       ip ioam namespace del ID\n"
  30                "       ip ioam schema show\n"
  31                "       ip ioam schema add ID DATA\n"
  32                "       ip ioam schema del ID\n"
  33                "       ip ioam namespace set ID schema { ID | none }\n");
  34        exit(-1);
  35}
  36
  37static struct rtnl_handle grth = { .fd = -1 };
  38static int genl_family = -1;
  39
  40#define IOAM6_REQUEST(_req, _bufsiz, _cmd, _flags) \
  41         GENL_REQUEST(_req, _bufsiz, genl_family, 0, \
  42                                IOAM6_GENL_VERSION, _cmd, _flags)
  43
  44static struct {
  45        unsigned int cmd;
  46        __u32 sc_id;
  47        __u32 ns_data;
  48        __u64 ns_data_wide;
  49        __u16 ns_id;
  50        bool has_ns_data;
  51        bool has_ns_data_wide;
  52        bool sc_none;
  53        __u8 sc_data[IOAM6_MAX_SCHEMA_DATA_LEN];
  54} opts;
  55
  56static void print_namespace(struct rtattr *attrs[])
  57{
  58        print_uint(PRINT_ANY, "namespace", "namespace %u",
  59                   rta_getattr_u16(attrs[IOAM6_ATTR_NS_ID]));
  60
  61        if (attrs[IOAM6_ATTR_SC_ID])
  62                print_uint(PRINT_ANY, "schema", " [schema %u]",
  63                           rta_getattr_u32(attrs[IOAM6_ATTR_SC_ID]));
  64
  65        if (attrs[IOAM6_ATTR_NS_DATA])
  66                print_hex(PRINT_ANY, "data", ", data %#010x",
  67                          rta_getattr_u32(attrs[IOAM6_ATTR_NS_DATA]));
  68
  69        if (attrs[IOAM6_ATTR_NS_DATA_WIDE])
  70                print_0xhex(PRINT_ANY, "wide", ", wide %#018lx",
  71                            rta_getattr_u64(attrs[IOAM6_ATTR_NS_DATA_WIDE]));
  72
  73        print_nl();
  74}
  75
  76static void print_schema(struct rtattr *attrs[])
  77{
  78        __u8 data[IOAM6_MAX_SCHEMA_DATA_LEN];
  79        int len, i = 0;
  80
  81        print_uint(PRINT_ANY, "schema", "schema %u",
  82                   rta_getattr_u32(attrs[IOAM6_ATTR_SC_ID]));
  83
  84        if (attrs[IOAM6_ATTR_NS_ID])
  85                print_uint(PRINT_ANY, "namespace", " [namespace %u]",
  86                           rta_getattr_u16(attrs[IOAM6_ATTR_NS_ID]));
  87
  88        len = RTA_PAYLOAD(attrs[IOAM6_ATTR_SC_DATA]);
  89        memcpy(data, RTA_DATA(attrs[IOAM6_ATTR_SC_DATA]), len);
  90
  91        print_null(PRINT_ANY, "data", ", data:", NULL);
  92        while (i < len) {
  93                print_hhu(PRINT_ANY, "", " %02x", data[i]);
  94                i++;
  95        }
  96        print_nl();
  97}
  98
  99static int process_msg(struct nlmsghdr *n, void *arg)
 100{
 101        struct rtattr *attrs[IOAM6_ATTR_MAX + 1];
 102        struct genlmsghdr *ghdr;
 103        int len = n->nlmsg_len;
 104
 105        if (n->nlmsg_type != genl_family)
 106                return -1;
 107
 108        len -= NLMSG_LENGTH(GENL_HDRLEN);
 109        if (len < 0)
 110                return -1;
 111
 112        ghdr = NLMSG_DATA(n);
 113        parse_rtattr(attrs, IOAM6_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
 114
 115        open_json_object(NULL);
 116        switch (ghdr->cmd) {
 117        case IOAM6_CMD_DUMP_NAMESPACES:
 118                print_namespace(attrs);
 119                break;
 120        case IOAM6_CMD_DUMP_SCHEMAS:
 121                print_schema(attrs);
 122                break;
 123        }
 124        close_json_object();
 125
 126        return 0;
 127}
 128
 129static int ioam6_do_cmd(void)
 130{
 131        IOAM6_REQUEST(req, 1056, opts.cmd, NLM_F_REQUEST);
 132        int dump = 0;
 133
 134        if (genl_init_handle(&grth, IOAM6_GENL_NAME, &genl_family))
 135                exit(1);
 136
 137        req.n.nlmsg_type = genl_family;
 138
 139        switch (opts.cmd) {
 140        case IOAM6_CMD_ADD_NAMESPACE:
 141                addattr16(&req.n, sizeof(req), IOAM6_ATTR_NS_ID, opts.ns_id);
 142                if (opts.has_ns_data)
 143                        addattr32(&req.n, sizeof(req), IOAM6_ATTR_NS_DATA,
 144                                  opts.ns_data);
 145                if (opts.has_ns_data_wide)
 146                        addattr64(&req.n, sizeof(req), IOAM6_ATTR_NS_DATA_WIDE,
 147                                  opts.ns_data_wide);
 148                break;
 149        case IOAM6_CMD_DEL_NAMESPACE:
 150                addattr16(&req.n, sizeof(req), IOAM6_ATTR_NS_ID, opts.ns_id);
 151                break;
 152        case IOAM6_CMD_DUMP_NAMESPACES:
 153        case IOAM6_CMD_DUMP_SCHEMAS:
 154                dump = 1;
 155                break;
 156        case IOAM6_CMD_ADD_SCHEMA:
 157                addattr32(&req.n, sizeof(req), IOAM6_ATTR_SC_ID, opts.sc_id);
 158                addattr_l(&req.n, sizeof(req), IOAM6_ATTR_SC_DATA, opts.sc_data,
 159                          strlen((const char *)opts.sc_data));
 160                break;
 161        case IOAM6_CMD_DEL_SCHEMA:
 162                addattr32(&req.n, sizeof(req), IOAM6_ATTR_SC_ID, opts.sc_id);
 163                break;
 164        case IOAM6_CMD_NS_SET_SCHEMA:
 165                addattr16(&req.n, sizeof(req), IOAM6_ATTR_NS_ID, opts.ns_id);
 166                if (opts.sc_none)
 167                        addattr(&req.n, sizeof(req), IOAM6_ATTR_SC_NONE);
 168                else
 169                        addattr32(&req.n, sizeof(req), IOAM6_ATTR_SC_ID,
 170                                  opts.sc_id);
 171                break;
 172        }
 173
 174        if (!dump) {
 175                if (rtnl_talk(&grth, &req.n, NULL) < 0)
 176                        return -1;
 177        } else {
 178                req.n.nlmsg_flags |= NLM_F_DUMP;
 179                req.n.nlmsg_seq = grth.dump = ++grth.seq;
 180                if (rtnl_send(&grth, &req, req.n.nlmsg_len) < 0) {
 181                        perror("Failed to send dump request");
 182                        exit(1);
 183                }
 184
 185                new_json_obj(json);
 186                if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) {
 187                        fprintf(stderr, "Dump terminated\n");
 188                        exit(1);
 189                }
 190                delete_json_obj();
 191                fflush(stdout);
 192        }
 193
 194        return 0;
 195}
 196
 197int do_ioam6(int argc, char **argv)
 198{
 199        bool maybe_wide = false;
 200
 201        if (argc < 1 || strcmp(*argv, "help") == 0)
 202                usage();
 203
 204        memset(&opts, 0, sizeof(opts));
 205
 206        if (strcmp(*argv, "namespace") == 0) {
 207                NEXT_ARG();
 208
 209                if (strcmp(*argv, "show") == 0) {
 210                        opts.cmd = IOAM6_CMD_DUMP_NAMESPACES;
 211
 212                } else if (strcmp(*argv, "add") == 0) {
 213                        NEXT_ARG();
 214
 215                        if (get_u16(&opts.ns_id, *argv, 0))
 216                                invarg("Invalid namespace ID", *argv);
 217
 218                        if (NEXT_ARG_OK()) {
 219                                NEXT_ARG_FWD();
 220
 221                                if (strcmp(*argv, "data") == 0) {
 222                                        NEXT_ARG();
 223
 224                                        if (get_u32(&opts.ns_data, *argv, 0))
 225                                                invarg("Invalid data", *argv);
 226
 227                                        maybe_wide = true;
 228                                        opts.has_ns_data = true;
 229
 230                                } else if (strcmp(*argv, "wide") == 0) {
 231                                        NEXT_ARG();
 232
 233                                        if (get_u64(&opts.ns_data_wide, *argv, 16))
 234                                                invarg("Invalid wide data", *argv);
 235
 236                                        opts.has_ns_data_wide = true;
 237
 238                                } else {
 239                                        invarg("Invalid argument", *argv);
 240                                }
 241                        }
 242
 243                        if (NEXT_ARG_OK()) {
 244                                NEXT_ARG_FWD();
 245
 246                                if (!maybe_wide || strcmp(*argv, "wide") != 0)
 247                                        invarg("Unexpected argument", *argv);
 248
 249                                NEXT_ARG();
 250
 251                                if (get_u64(&opts.ns_data_wide, *argv, 16))
 252                                        invarg("Invalid wide data", *argv);
 253
 254                                opts.has_ns_data_wide = true;
 255                        }
 256
 257                        opts.cmd = IOAM6_CMD_ADD_NAMESPACE;
 258
 259                } else if (strcmp(*argv, "del") == 0) {
 260                        NEXT_ARG();
 261
 262                        if (get_u16(&opts.ns_id, *argv, 0))
 263                                invarg("Invalid namespace ID", *argv);
 264
 265                        opts.cmd = IOAM6_CMD_DEL_NAMESPACE;
 266
 267                } else if (strcmp(*argv, "set") == 0) {
 268                        NEXT_ARG();
 269
 270                        if (get_u16(&opts.ns_id, *argv, 0))
 271                                invarg("Invalid namespace ID", *argv);
 272
 273                        NEXT_ARG();
 274
 275                        if (strcmp(*argv, "schema") != 0)
 276                                invarg("Unknown", *argv);
 277
 278                        NEXT_ARG();
 279
 280                        if (strcmp(*argv, "none") == 0) {
 281                                opts.sc_none = true;
 282
 283                        } else {
 284                                if (get_u32(&opts.sc_id, *argv, 0))
 285                                        invarg("Invalid schema ID", *argv);
 286
 287                                opts.sc_none = false;
 288                        }
 289
 290                        opts.cmd = IOAM6_CMD_NS_SET_SCHEMA;
 291
 292                } else {
 293                        invarg("Unknown", *argv);
 294                }
 295
 296        } else if (strcmp(*argv, "schema") == 0) {
 297                NEXT_ARG();
 298
 299                if (strcmp(*argv, "show") == 0) {
 300                        opts.cmd = IOAM6_CMD_DUMP_SCHEMAS;
 301
 302                } else if (strcmp(*argv, "add") == 0) {
 303                        NEXT_ARG();
 304
 305                        if (get_u32(&opts.sc_id, *argv, 0))
 306                                invarg("Invalid schema ID", *argv);
 307
 308                        NEXT_ARG();
 309
 310                        if (strlen(*argv) > IOAM6_MAX_SCHEMA_DATA_LEN)
 311                                invarg("Schema DATA too big", *argv);
 312
 313                        memcpy(opts.sc_data, *argv, strlen(*argv));
 314                        opts.cmd = IOAM6_CMD_ADD_SCHEMA;
 315
 316                } else if (strcmp(*argv, "del") == 0) {
 317                        NEXT_ARG();
 318
 319                        if (get_u32(&opts.sc_id, *argv, 0))
 320                                invarg("Invalid schema ID", *argv);
 321
 322                        opts.cmd = IOAM6_CMD_DEL_SCHEMA;
 323
 324                } else {
 325                        invarg("Unknown", *argv);
 326                }
 327
 328        } else {
 329                invarg("Unknown", *argv);
 330        }
 331
 332        return ioam6_do_cmd();
 333}
 334