iproute2/ip/ipaddrlabel.c
<<
>>
Prefs
   1/*
   2 * ipaddrlabel.c        "ip addrlabel"
   3 *
   4 * Copyright (C)2007 USAGI/WIDE Project
   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 2 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 *
  19 *
  20 * Based on iprule.c.
  21 *
  22 * Authors:     YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
  23 *
  24 */
  25
  26#include <stdio.h>
  27#include <stdlib.h>
  28#include <unistd.h>
  29#include <fcntl.h>
  30#include <sys/socket.h>
  31#include <netinet/in.h>
  32#include <netinet/ip.h>
  33#include <arpa/inet.h>
  34#include <string.h>
  35#include <linux/types.h>
  36#include <linux/if_addrlabel.h>
  37
  38#include "rt_names.h"
  39#include "utils.h"
  40#include "ip_common.h"
  41#include "json_print.h"
  42
  43#define IFAL_RTA(r)     ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))))
  44#define IFAL_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct ifaddrlblmsg))
  45
  46extern struct rtnl_handle rth;
  47
  48static void usage(void) __attribute__((noreturn));
  49
  50static void usage(void)
  51{
  52        fprintf(stderr,
  53                "Usage: ip addrlabel { add | del } prefix PREFIX [ dev DEV ] [ label LABEL ]\n"
  54                "       ip addrlabel [ list | flush | help ]\n");
  55        exit(-1);
  56}
  57
  58int print_addrlabel(struct nlmsghdr *n, void *arg)
  59{
  60        struct ifaddrlblmsg *ifal = NLMSG_DATA(n);
  61        int len = n->nlmsg_len;
  62        struct rtattr *tb[IFAL_MAX+1];
  63
  64        if (n->nlmsg_type != RTM_NEWADDRLABEL && n->nlmsg_type != RTM_DELADDRLABEL)
  65                return 0;
  66
  67        len -= NLMSG_LENGTH(sizeof(*ifal));
  68        if (len < 0)
  69                return -1;
  70
  71        parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
  72
  73        open_json_object(NULL);
  74        if (n->nlmsg_type == RTM_DELADDRLABEL)
  75                print_bool(PRINT_ANY, "deleted", "Deleted ", true);
  76
  77        if (tb[IFAL_ADDRESS]) {
  78                const char *host
  79                        = format_host_rta(ifal->ifal_family,
  80                                          tb[IFAL_ADDRESS]);
  81
  82                print_string(PRINT_FP, NULL, "prefix ", NULL);
  83                print_color_string(PRINT_ANY,
  84                                   ifa_family_color(ifal->ifal_family),
  85                                   "address", "%s", host);
  86
  87                print_uint(PRINT_ANY, "prefixlen", "/%u ",
  88                           ifal->ifal_prefixlen);
  89        }
  90
  91        if (ifal->ifal_index) {
  92                print_string(PRINT_FP, NULL, "dev ", NULL);
  93                print_color_string(PRINT_ANY, COLOR_IFNAME,
  94                                   "ifname", "%s ",
  95                                   ll_index_to_name(ifal->ifal_index));
  96        }
  97
  98        if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(uint32_t)) {
  99                uint32_t label = rta_getattr_u32(tb[IFAL_LABEL]);
 100
 101                print_uint(PRINT_ANY,
 102                           "label", "label %u ", label);
 103        }
 104        print_string(PRINT_FP, NULL, "\n", "");
 105        close_json_object();
 106
 107        return 0;
 108}
 109
 110static int ipaddrlabel_list(int argc, char **argv)
 111{
 112        int af = preferred_family;
 113
 114        if (af == AF_UNSPEC)
 115                af = AF_INET6;
 116
 117        if (argc > 0) {
 118                fprintf(stderr, "\"ip addrlabel show\" does not take any arguments.\n");
 119                return -1;
 120        }
 121
 122        if (rtnl_addrlbldump_req(&rth, af) < 0) {
 123                perror("Cannot send dump request");
 124                return 1;
 125        }
 126
 127        new_json_obj(json);
 128        if (rtnl_dump_filter(&rth, print_addrlabel, stdout) < 0) {
 129                fprintf(stderr, "Dump terminated\n");
 130                return 1;
 131        }
 132        delete_json_obj();
 133
 134        return 0;
 135}
 136
 137
 138static int ipaddrlabel_modify(int cmd, int argc, char **argv)
 139{
 140        struct {
 141                struct nlmsghdr n;
 142                struct ifaddrlblmsg     ifal;
 143                char                    buf[1024];
 144        } req = {
 145                .n.nlmsg_type = cmd,
 146                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)),
 147                .n.nlmsg_flags = NLM_F_REQUEST,
 148                .ifal.ifal_family = preferred_family,
 149        };
 150
 151        inet_prefix prefix = {};
 152        uint32_t label = 0xffffffffUL;
 153        char *p = NULL;
 154        char *l = NULL;
 155
 156        if (cmd == RTM_NEWADDRLABEL) {
 157                req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
 158        }
 159
 160        while (argc > 0) {
 161                if (strcmp(*argv, "prefix") == 0) {
 162                        NEXT_ARG();
 163                        p = *argv;
 164                        get_prefix(&prefix, *argv, preferred_family);
 165                } else if (strcmp(*argv, "dev") == 0) {
 166                        NEXT_ARG();
 167                        if ((req.ifal.ifal_index = ll_name_to_index(*argv)) == 0)
 168                                invarg("dev is invalid\n", *argv);
 169                } else if (strcmp(*argv, "label") == 0) {
 170                        NEXT_ARG();
 171                        l = *argv;
 172                        if (get_u32(&label, *argv, 0) || label == 0xffffffffUL)
 173                                invarg("label is invalid\n", *argv);
 174                }
 175                argc--;
 176                argv++;
 177        }
 178        if (p == NULL) {
 179                fprintf(stderr, "Not enough information: \"prefix\" argument is required.\n");
 180                return -1;
 181        }
 182        if (l == NULL) {
 183                fprintf(stderr, "Not enough information: \"label\" argument is required.\n");
 184                return -1;
 185        }
 186        addattr32(&req.n, sizeof(req), IFAL_LABEL, label);
 187        addattr_l(&req.n, sizeof(req), IFAL_ADDRESS, &prefix.data, prefix.bytelen);
 188        req.ifal.ifal_prefixlen = prefix.bitlen;
 189
 190        if (req.ifal.ifal_family == AF_UNSPEC)
 191                req.ifal.ifal_family = AF_INET6;
 192
 193        if (rtnl_talk(&rth, &req.n, NULL) < 0)
 194                return -2;
 195
 196        return 0;
 197}
 198
 199
 200static int flush_addrlabel(struct nlmsghdr *n, void *arg)
 201{
 202        struct rtnl_handle rth2;
 203        struct rtmsg *r = NLMSG_DATA(n);
 204        int len = n->nlmsg_len;
 205        struct rtattr *tb[IFAL_MAX+1];
 206
 207        len -= NLMSG_LENGTH(sizeof(*r));
 208        if (len < 0)
 209                return -1;
 210
 211        parse_rtattr(tb, IFAL_MAX, RTM_RTA(r), len);
 212
 213        if (tb[IFAL_ADDRESS]) {
 214                n->nlmsg_type = RTM_DELADDRLABEL;
 215                n->nlmsg_flags = NLM_F_REQUEST;
 216
 217                if (rtnl_open(&rth2, 0) < 0)
 218                        return -1;
 219
 220                if (rtnl_talk(&rth2, n, NULL) < 0)
 221                        return -2;
 222
 223                rtnl_close(&rth2);
 224        }
 225
 226        return 0;
 227}
 228
 229static int ipaddrlabel_flush(int argc, char **argv)
 230{
 231        int af = preferred_family;
 232
 233        if (af == AF_UNSPEC)
 234                af = AF_INET6;
 235
 236        if (argc > 0) {
 237                fprintf(stderr, "\"ip addrlabel flush\" does not allow extra arguments\n");
 238                return -1;
 239        }
 240
 241        if (rtnl_addrlbldump_req(&rth, af) < 0) {
 242                perror("Cannot send dump request");
 243                return -1;
 244        }
 245
 246        if (rtnl_dump_filter(&rth, flush_addrlabel, NULL) < 0) {
 247                fprintf(stderr, "Flush terminated\n");
 248                return -1;
 249        }
 250
 251        return 0;
 252}
 253
 254int do_ipaddrlabel(int argc, char **argv)
 255{
 256        if (argc < 1) {
 257                return ipaddrlabel_list(0, NULL);
 258        } else if (matches(argv[0], "list") == 0 ||
 259                   matches(argv[0], "lst") == 0 ||
 260                   matches(argv[0], "show") == 0) {
 261                return ipaddrlabel_list(argc-1, argv+1);
 262        } else if (matches(argv[0], "add") == 0) {
 263                return ipaddrlabel_modify(RTM_NEWADDRLABEL, argc-1, argv+1);
 264        } else if (matches(argv[0], "delete") == 0) {
 265                return ipaddrlabel_modify(RTM_DELADDRLABEL, argc-1, argv+1);
 266        } else if (matches(argv[0], "flush") == 0) {
 267                return ipaddrlabel_flush(argc-1, argv+1);
 268        } else if (matches(argv[0], "help") == 0)
 269                usage();
 270
 271        fprintf(stderr, "Command \"%s\" is unknown, try \"ip addrlabel help\".\n", *argv);
 272        exit(-1);
 273}
 274