]> git.ipfire.org Git - thirdparty/iproute2.git/commitdiff
ip: ipv6: add tokenized interface identifier support
authorDaniel Borkmann <dborkman@redhat.com>
Tue, 30 Apr 2013 06:22:50 +0000 (06:22 +0000)
committerStephen Hemminger <stephen@networkplumber.org>
Fri, 3 May 2013 20:17:21 +0000 (13:17 -0700)
This patch adds support for tokenized IIDs, that enable
administrators to assign well-known host-part addresses
to nodes whilst still obtaining global network prefix
from Router Advertisements. This is the iproute2 part for
the kernel patch f53adae4eae5 (``net: ipv6: add tokenized
interface identifier support'').

Example commands with iproute2:

Setting a device token:
  # ip token set ::1a:2b:3c:4d/64 dev eth1

Getting a device token:
  # ip token get dev eth1
  token ::1a:2b:3c:4d dev eth1

Listing all tokens:
  # ip token list  (or: ip token)
  token :: dev eth0
  token ::1a:2b:3c:4d dev eth1

Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
ip/Makefile
ip/ip.c
ip/ip_common.h
ip/iptoken.c [new file with mode: 0644]
man/man8/Makefile
man/man8/ip-token.8 [new file with mode: 0644]

index 2b606d4771c7ed4b57faa5ba8120a68096a13268..48bd4a16e0c5b41e363a781f9925ddf9892693b2 100644 (file)
@@ -1,6 +1,6 @@
 IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o ipnetns.o \
     rtm_map.o iptunnel.o ip6tunnel.o tunnel.o ipneigh.o ipntable.o iplink.o \
-    ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o iptuntap.o \
+    ipmaddr.o ipmonitor.o ipmroute.o ipprefix.o iptuntap.o iptoken.o \
     ipxfrm.o xfrm_state.o xfrm_policy.o xfrm_monitor.o \
     iplink_vlan.o link_veth.o link_gre.o iplink_can.o \
     iplink_macvlan.o iplink_macvtap.o ipl2tp.o link_vti.o \
diff --git a/ip/ip.c b/ip/ip.c
index e10ddb2f831091cccca0d279fe636610be5b5f6c..69bd5ffb93a5bf9d2d9dec1d70cbd6d464a82e59 100644 (file)
--- a/ip/ip.c
+++ b/ip/ip.c
@@ -45,7 +45,7 @@ static void usage(void)
 "       ip [ -force ] -batch filename\n"
 "where  OBJECT := { link | addr | addrlabel | route | rule | neigh | ntable |\n"
 "                   tunnel | tuntap | maddr | mroute | mrule | monitor | xfrm |\n"
-"                   netns | l2tp | tcp_metrics }\n"
+"                   netns | l2tp | tcp_metrics | token }\n"
 "       OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] |\n"
 "                    -f[amily] { inet | inet6 | ipx | dnet | bridge | link } |\n"
 "                    -4 | -6 | -I | -D | -B | -0 |\n"
@@ -80,6 +80,7 @@ static const struct cmd {
        { "tunl",       do_iptunnel },
        { "tuntap",     do_iptuntap },
        { "tap",        do_iptuntap },
+       { "token",      do_iptoken },
        { "tcpmetrics", do_tcp_metrics },
        { "tcp_metrics",do_tcp_metrics },
        { "monitor",    do_ipmonitor },
index de568101547f0a6ce7339a2e75519a9485d7c0da..f9b47343494194eb0d2ed2b33d7b87b58f571852 100644 (file)
@@ -49,6 +49,7 @@ extern int do_xfrm(int argc, char **argv);
 extern int do_ipl2tp(int argc, char **argv);
 extern int do_tcp_metrics(int argc, char **argv);
 extern int do_ipnetconf(int argc, char **argv);
+extern int do_iptoken(int argc, char **argv);
 
 static inline int rtm_get_table(struct rtmsg *r, struct rtattr **tb)
 {
diff --git a/ip/iptoken.c b/ip/iptoken.c
new file mode 100644 (file)
index 0000000..5689c2e
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * iptoken.c    "ip token"
+ *
+ *              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.
+ *
+ * Authors:     Daniel Borkmann, <borkmann@redhat.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <arpa/inet.h>
+#include <linux/types.h>
+#include <linux/if.h>
+
+#include "rt_names.h"
+#include "utils.h"
+#include "ip_common.h"
+
+extern struct rtnl_handle rth;
+
+struct rtnl_dump_args {
+       FILE *fp;
+       int ifindex;
+};
+
+static void usage(void) __attribute__((noreturn));
+
+static void usage(void)
+{
+       fprintf(stderr, "Usage: ip token [ list | set | get ] [ TOKEN ] [ dev DEV ]\n");
+       exit(-1);
+}
+
+static int print_token(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+       struct rtnl_dump_args *args = arg;
+       FILE *fp = args->fp;
+       int ifindex = args->ifindex;
+       struct ifinfomsg *ifi = NLMSG_DATA(n);
+       int len = n->nlmsg_len;
+       struct rtattr *tb[IFLA_MAX + 1];
+       struct rtattr *ltb[IFLA_INET6_MAX + 1];
+       char abuf[256];
+
+       if (n->nlmsg_type != RTM_NEWLINK)
+               return -1;
+
+       len -= NLMSG_LENGTH(sizeof(*ifi));
+       if (len < 0)
+               return -1;
+
+       if (ifi->ifi_family != AF_INET6)
+               return -1;
+       if (ifi->ifi_index == 0)
+               return -1;
+       if (ifindex > 0 && ifi->ifi_index != ifindex)
+               return 0;
+       if (ifi->ifi_flags & (IFF_LOOPBACK | IFF_NOARP))
+               return 0;
+
+       parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
+       if (!tb[IFLA_PROTINFO])
+               return -1;
+
+       parse_rtattr_nested(ltb, IFLA_INET6_MAX, tb[IFLA_PROTINFO]);
+       if (!ltb[IFLA_INET6_TOKEN]) {
+               fprintf(stderr, "Seems there's no support for IPv6 token!\n");
+               return -1;
+       }
+
+       fprintf(fp, "token %s ",
+               format_host(ifi->ifi_family,
+                           RTA_PAYLOAD(ltb[IFLA_INET6_TOKEN]),
+                           RTA_DATA(ltb[IFLA_INET6_TOKEN]),
+                           abuf, sizeof(abuf)));
+       fprintf(fp, "dev %s ", ll_index_to_name(ifi->ifi_index));
+       fprintf(fp, "\n");
+       fflush(fp);
+
+       return 0;
+}
+
+static int iptoken_list(int argc, char **argv)
+{
+       int af = AF_INET6;
+       struct rtnl_dump_args da;
+       const struct rtnl_dump_filter_arg a[2] = {
+               { .filter = print_token, .arg1 = &da, },
+               { .filter = NULL, .arg1 = NULL, },
+       };
+
+       memset(&da, 0, sizeof(da));
+       da.fp = stdout;
+
+       while (argc > 0) {
+               if (strcmp(*argv, "dev") == 0) {
+                       NEXT_ARG();
+                       if ((da.ifindex = ll_name_to_index(*argv)) == 0)
+                               invarg("dev is invalid\n", *argv);
+                       break;
+               }
+               argc--; argv++;
+       }
+
+       if (rtnl_wilddump_request(&rth, af, RTM_GETLINK) < 0) {
+               perror("Cannot send dump request");
+               return -1;
+       }
+
+       if (rtnl_dump_filter_l(&rth, a) < 0) {
+               fprintf(stderr, "Dump terminated\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static int iptoken_set(int argc, char **argv)
+{
+       struct {
+               struct nlmsghdr n;
+               struct ifinfomsg ifi;
+               char buf[512];
+       } req;
+       struct rtattr *afs, *afs6;
+       bool have_token = false, have_dev = false;
+       inet_prefix addr;
+
+       memset(&addr, 0, sizeof(addr));
+       memset(&req, 0, sizeof(req));
+
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_type = RTM_SETLINK;
+       req.ifi.ifi_family = AF_INET6;
+
+       while (argc > 0) {
+               if (strcmp(*argv, "dev") == 0) {
+                       NEXT_ARG();
+                       if (!have_dev) {
+                               if ((req.ifi.ifi_index =
+                                    ll_name_to_index(*argv)) == 0)
+                                       invarg("dev is invalid\n", *argv);
+                               have_dev = true;
+                       }
+               } else {
+                       if (matches(*argv, "help") == 0)
+                               usage();
+                       if (!have_token) {
+                               afs = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
+                               afs6 = addattr_nest(&req.n, sizeof(req), AF_INET6);
+                               get_prefix(&addr, *argv, req.ifi.ifi_family);
+                               addattr_l(&req.n, sizeof(req), IFLA_INET6_TOKEN,
+                                         &addr.data, addr.bytelen);
+                               addattr_nest_end(&req.n, afs6);
+                               addattr_nest_end(&req.n, afs);
+                               have_token = true;
+                       }
+               }
+               argc--; argv++;
+       }
+
+       if (!have_token) {
+               fprintf(stderr, "Not enough information: token "
+                       "is required.\n");
+               return -1;
+       }
+       if (!have_dev) {
+               fprintf(stderr, "Not enough information: \"dev\" "
+                       "argument is required.\n");
+               return -1;
+       }
+
+       if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+               return -2;
+
+       return 0;
+}
+
+int do_iptoken(int argc, char **argv)
+{
+       ll_init_map(&rth);
+
+       if (argc < 1) {
+               return iptoken_list(0, NULL);
+       } else if (matches(argv[0], "list") == 0 ||
+                  matches(argv[0], "show") == 0) {
+               return iptoken_list(argc - 1, argv + 1);
+       } else if (matches(argv[0], "set") == 0 ||
+                  matches(argv[0], "add") == 0) {
+               return iptoken_set(argc - 1, argv + 1);
+       } else if (matches(argv[0], "get") == 0) {
+               return iptoken_list(argc - 1, argv + 1);
+       } else if (matches(argv[0], "help") == 0)
+               usage();
+
+       fprintf(stderr, "Command \"%s\" is unknown, try \"ip token help\".\n", *argv);
+       exit(-1);
+}
index d208f3b03109e5abcf9b5c637e5a17dc8a69b3da..ff80c9884f50c24e422d0519b3eaa269b125e400 100644 (file)
@@ -9,7 +9,7 @@ MAN8PAGES = $(TARGETS) ip.8 arpd.8 lnstat.8 routel.8 rtacct.8 rtmon.8 ss.8 \
        ip-addrlabel.8 ip-l2tp.8 \
        ip-maddress.8 ip-monitor.8 ip-mroute.8 ip-neighbour.8 \
        ip-netns.8 ip-ntable.8 ip-rule.8 ip-tunnel.8 ip-xfrm.8 \
-       ip-tcp_metrics.8 ip-netconf.8
+       ip-tcp_metrics.8 ip-netconf.8 ip-token.8
 
 all: $(TARGETS)
 
diff --git a/man/man8/ip-token.8 b/man/man8/ip-token.8
new file mode 100644 (file)
index 0000000..521596f
--- /dev/null
@@ -0,0 +1,66 @@
+.TH IP\-TOKEN 8 "28 Mar 2013" "iproute2" "Linux"
+.SH "NAME"
+ip-token \- tokenized interface identifer support
+.SH "SYNOPSIS"
+.sp
+.ad l
+.in +8
+.ti -8
+.B ip token
+.RI " { " COMMAND " | "
+.BR help " }"
+.sp
+
+.ti -8
+.BR "ip token" " { " set " } "
+.IR TOKEN
+.B dev
+.IR DEV
+
+.ti -8
+.BR "ip token" " { " get " } "
+.B dev
+.IR DEV
+
+.ti -8
+.BR "ip token" " { " list " }"
+
+.SH "DESCRIPTION"
+IPv6 tokenized interface identifer support is used for assigning well-known
+host-part addresses to nodes whilst still obtaining a global network prefix
+from Router advertisements. The primary target for tokenized identifiers are
+server platforms where addresses are usually manually configured, rather than
+using DHCPv6 or SLAAC. By using tokenized identifiers, hosts can still
+determine their network prefix by use of SLAAC, but more readily be
+automatically renumbered should their network prefix change [1]. Tokenized
+IPv6 Identifiers are described in the draft
+[1]: <draft-chown-6man-tokenised-ipv6-identifiers-02>.
+
+.SS ip token set - set an interface token
+set the interface token to the kernel. Once a token is set, it cannot be
+removed from the interface, only overwritten.
+.TP
+.I TOKEN
+the interface identifer token address.
+.TP
+.BI dev " DEV"
+the networking interface.
+
+.SS ip token get - get the interface token from the kernel
+show a tokenized interface identifer of a particular networking device.
+.B Arguments:
+coincide with the arguments of
+.B ip token set
+but the
+.I TOKEN
+must be left out.
+.SS ip token list - list all interface tokens
+list all tokenized interface identifers for the networking interfaces from
+the kernel.
+
+.SH SEE ALSO
+.br
+.BR ip (8)
+
+.SH AUTHOR
+Manpage by Daniel Borkmann