summaryrefslogtreecommitdiffstats
path: root/ip/iplink_amt.c
diff options
context:
space:
mode:
Diffstat (limited to 'ip/iplink_amt.c')
-rw-r--r--ip/iplink_amt.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/ip/iplink_amt.c b/ip/iplink_amt.c
new file mode 100644
index 0000000..3a35bd9
--- /dev/null
+++ b/ip/iplink_amt.c
@@ -0,0 +1,196 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * iplink_amt.c AMT device support
+ *
+ * Authors: Taehee Yoo <ap420073@gmail.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <net/if.h>
+#include <linux/ip.h>
+#include <linux/if_link.h>
+#include <arpa/inet.h>
+#include <linux/amt.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+#define AMT_ATTRSET(attrs, type) (((attrs) & (1L << (type))) != 0)
+
+static void print_usage(FILE *f)
+{
+ fprintf(f,
+ "Usage: ... amt\n"
+ " [ discovery IP_ADDRESS ]\n"
+ " [ mode MODE ]\n"
+ " [ local ADDR ]\n"
+ " [ dev PHYS_DEV ]\n"
+ " [ relay_port PORT ]\n"
+ " [ gateway_port PORT ]\n"
+ " [ max_tunnels NUMBER ]\n"
+ "\n"
+ "Where: ADDR := { IP_ADDRESS }\n"
+ " MODE := { gateway | relay }\n"
+ );
+}
+
+static char *modename[] = {"gateway", "relay"};
+
+static void usage(void)
+{
+ print_usage(stderr);
+}
+
+static void check_duparg(__u64 *attrs, int type, const char *key,
+ const char *argv)
+{
+ if (!AMT_ATTRSET(*attrs, type)) {
+ *attrs |= (1L << type);
+ return;
+ }
+ duparg2(key, argv);
+}
+
+static int amt_parse_opt(struct link_util *lu, int argc, char **argv,
+ struct nlmsghdr *n)
+{
+ unsigned int mode, max_tunnels;
+ inet_prefix saddr, daddr;
+ __u64 attrs = 0;
+ __u16 port;
+
+ saddr.family = daddr.family = AF_UNSPEC;
+
+ inet_prefix_reset(&saddr);
+ inet_prefix_reset(&daddr);
+
+ while (argc > 0) {
+ if (strcmp(*argv, "mode") == 0) {
+ NEXT_ARG();
+ if (strcmp(*argv, "gateway") == 0) {
+ mode = 0;
+ } else if (strcmp(*argv, "relay") == 0) {
+ mode = 1;
+ } else {
+ usage();
+ return -1;
+ }
+ addattr32(n, 1024, IFLA_AMT_MODE, mode);
+ } else if (strcmp(*argv, "relay_port") == 0) {
+ NEXT_ARG();
+ if (get_u16(&port, *argv, 0))
+ invarg("relay_port", *argv);
+ addattr16(n, 1024, IFLA_AMT_RELAY_PORT, htons(port));
+ } else if (strcmp(*argv, "gateway_port") == 0) {
+ NEXT_ARG();
+ if (get_u16(&port, *argv, 0))
+ invarg("gateway_port", *argv);
+ addattr16(n, 1024, IFLA_AMT_GATEWAY_PORT, htons(port));
+ } else if (strcmp(*argv, "max_tunnels") == 0) {
+ NEXT_ARG();
+ if (get_u32(&max_tunnels, *argv, 0))
+ invarg("max_tunnels", *argv);
+ addattr32(n, 1024, IFLA_AMT_MAX_TUNNELS, max_tunnels);
+ } else if (strcmp(*argv, "dev") == 0) {
+ unsigned int link;
+
+ NEXT_ARG();
+ link = ll_name_to_index(*argv);
+ if (!link)
+ exit(nodev(*argv));
+ addattr32(n, 1024, IFLA_AMT_LINK, link);
+ } else if (strcmp(*argv, "local") == 0) {
+ NEXT_ARG();
+ check_duparg(&attrs, IFLA_AMT_LOCAL_IP, "local", *argv);
+ get_addr(&saddr, *argv, daddr.family);
+
+ if (is_addrtype_inet(&saddr))
+ addattr_l(n, 1024, IFLA_AMT_LOCAL_IP,
+ saddr.data, saddr.bytelen);
+ } else if (strcmp(*argv, "discovery") == 0) {
+ NEXT_ARG();
+ check_duparg(&attrs, IFLA_AMT_DISCOVERY_IP,
+ "discovery", *argv);
+ get_addr(&daddr, *argv, daddr.family);
+ if (is_addrtype_inet(&daddr))
+ addattr_l(n, 1024, IFLA_AMT_DISCOVERY_IP,
+ daddr.data, daddr.bytelen);
+ } else if (strcmp(*argv, "help") == 0) {
+ usage();
+ return -1;
+ } else {
+ fprintf(stderr, "amt: unknown command \"%s\"?\n", *argv);
+ usage();
+ return -1;
+ }
+ argc--, argv++;
+ }
+
+ return 0;
+}
+
+static void amt_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[])
+{
+ if (!tb)
+ return;
+
+ if (tb[IFLA_AMT_MODE])
+ print_string(PRINT_ANY, "mode", "%s ",
+ modename[rta_getattr_u32(tb[IFLA_AMT_MODE])]);
+
+ if (tb[IFLA_AMT_GATEWAY_PORT])
+ print_uint(PRINT_ANY, "gateway_port", "gateway_port %u ",
+ rta_getattr_be16(tb[IFLA_AMT_GATEWAY_PORT]));
+
+ if (tb[IFLA_AMT_RELAY_PORT])
+ print_uint(PRINT_ANY, "relay_port", "relay_port %u ",
+ rta_getattr_be16(tb[IFLA_AMT_RELAY_PORT]));
+
+ if (tb[IFLA_AMT_LOCAL_IP]) {
+ __be32 addr = rta_getattr_u32(tb[IFLA_AMT_LOCAL_IP]);
+
+ print_string(PRINT_ANY, "local", "local %s ",
+ format_host(AF_INET, 4, &addr));
+ }
+
+ if (tb[IFLA_AMT_REMOTE_IP]) {
+ __be32 addr = rta_getattr_u32(tb[IFLA_AMT_REMOTE_IP]);
+
+ print_string(PRINT_ANY, "remote", "remote %s ",
+ format_host(AF_INET, 4, &addr));
+ }
+
+ if (tb[IFLA_AMT_DISCOVERY_IP]) {
+ __be32 addr = rta_getattr_u32(tb[IFLA_AMT_DISCOVERY_IP]);
+
+ print_string(PRINT_ANY, "discovery", "discovery %s ",
+ format_host(AF_INET, 4, &addr));
+ }
+
+ if (tb[IFLA_AMT_LINK]) {
+ unsigned int link = rta_getattr_u32(tb[IFLA_AMT_LINK]);
+
+ print_string(PRINT_ANY, "link", "dev %s ",
+ ll_index_to_name(link));
+ }
+
+ if (tb[IFLA_AMT_MAX_TUNNELS])
+ print_uint(PRINT_ANY, "max_tunnels", "max_tunnels %u ",
+ rta_getattr_u32(tb[IFLA_AMT_MAX_TUNNELS]));
+}
+
+static void amt_print_help(struct link_util *lu, int argc, char **argv, FILE *f)
+{
+ print_usage(f);
+}
+
+struct link_util amt_link_util = {
+ .id = "amt",
+ .maxattr = IFLA_AMT_MAX,
+ .parse_opt = amt_parse_opt,
+ .print_opt = amt_print_opt,
+ .print_help = amt_print_help,
+};