mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-11-03 14:14:16 +00:00
This is an update for 460c03f3f3 ("iplink: double the buffer size also in
iplink_get()"). After update, we will not need to double the buffer size
every time when VFs number increased.
With call like rtnl_talk(&rth, &req.n, NULL, 0), we can simply remove the
length parameter.
With call like rtnl_talk(&rth, nlh, nlh, sizeof(req), I add a new variable
answer to avoid overwrite data in nlh, because it may has more info after
nlh. also this will avoid nlh buffer not enough issue.
We need to free answer after using.
Signed-off-by: Hangbin Liu <liuhangbin@gmail.com>
Signed-off-by: Phil Sutter <phil@nwl.cc>
260 lines
6.2 KiB
C
260 lines
6.2 KiB
C
/*
|
|
* ipaddrlabel.c "ip addrlabel"
|
|
*
|
|
* Copyright (C)2007 USAGI/WIDE Project
|
|
*
|
|
* 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.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, see <http://www.gnu.org/licenses>.
|
|
*
|
|
*
|
|
* Based on iprule.c.
|
|
*
|
|
* Authors: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <syslog.h>
|
|
#include <fcntl.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/ip.h>
|
|
#include <arpa/inet.h>
|
|
#include <string.h>
|
|
#include <linux/types.h>
|
|
#include <linux/if_addrlabel.h>
|
|
|
|
#include "rt_names.h"
|
|
#include "utils.h"
|
|
#include "ip_common.h"
|
|
|
|
#define IFAL_RTA(r) ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrlblmsg))))
|
|
#define IFAL_PAYLOAD(n) NLMSG_PAYLOAD(n, sizeof(struct ifaddrlblmsg))
|
|
|
|
extern struct rtnl_handle rth;
|
|
|
|
static void usage(void) __attribute__((noreturn));
|
|
|
|
static void usage(void)
|
|
{
|
|
fprintf(stderr, "Usage: ip addrlabel { add | del } prefix PREFIX [ dev DEV ] [ label LABEL ]\n");
|
|
fprintf(stderr, " ip addrlabel [ list | flush | help ]\n");
|
|
exit(-1);
|
|
}
|
|
|
|
int print_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
|
|
{
|
|
FILE *fp = (FILE *)arg;
|
|
struct ifaddrlblmsg *ifal = NLMSG_DATA(n);
|
|
int len = n->nlmsg_len;
|
|
struct rtattr *tb[IFAL_MAX+1];
|
|
|
|
if (n->nlmsg_type != RTM_NEWADDRLABEL && n->nlmsg_type != RTM_DELADDRLABEL)
|
|
return 0;
|
|
|
|
len -= NLMSG_LENGTH(sizeof(*ifal));
|
|
if (len < 0)
|
|
return -1;
|
|
|
|
parse_rtattr(tb, IFAL_MAX, IFAL_RTA(ifal), len);
|
|
|
|
if (n->nlmsg_type == RTM_DELADDRLABEL)
|
|
fprintf(fp, "Deleted ");
|
|
|
|
if (tb[IFAL_ADDRESS]) {
|
|
fprintf(fp, "prefix %s/%u ",
|
|
format_host_rta(ifal->ifal_family,
|
|
tb[IFAL_ADDRESS]),
|
|
ifal->ifal_prefixlen);
|
|
}
|
|
|
|
if (ifal->ifal_index)
|
|
fprintf(fp, "dev %s ", ll_index_to_name(ifal->ifal_index));
|
|
|
|
if (tb[IFAL_LABEL] && RTA_PAYLOAD(tb[IFAL_LABEL]) == sizeof(uint32_t)) {
|
|
uint32_t label;
|
|
|
|
memcpy(&label, RTA_DATA(tb[IFAL_LABEL]), sizeof(label));
|
|
fprintf(fp, "label %u ", label);
|
|
}
|
|
|
|
fprintf(fp, "\n");
|
|
fflush(fp);
|
|
return 0;
|
|
}
|
|
|
|
static int ipaddrlabel_list(int argc, char **argv)
|
|
{
|
|
int af = preferred_family;
|
|
|
|
if (af == AF_UNSPEC)
|
|
af = AF_INET6;
|
|
|
|
if (argc > 0) {
|
|
fprintf(stderr, "\"ip addrlabel show\" does not take any arguments.\n");
|
|
return -1;
|
|
}
|
|
|
|
if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
|
|
perror("Cannot send dump request");
|
|
return 1;
|
|
}
|
|
|
|
if (rtnl_dump_filter(&rth, print_addrlabel, stdout) < 0) {
|
|
fprintf(stderr, "Dump terminated\n");
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int ipaddrlabel_modify(int cmd, int argc, char **argv)
|
|
{
|
|
struct {
|
|
struct nlmsghdr n;
|
|
struct ifaddrlblmsg ifal;
|
|
char buf[1024];
|
|
} req = {
|
|
.n.nlmsg_type = cmd,
|
|
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrlblmsg)),
|
|
.n.nlmsg_flags = NLM_F_REQUEST,
|
|
.ifal.ifal_family = preferred_family,
|
|
};
|
|
|
|
inet_prefix prefix = {};
|
|
uint32_t label = 0xffffffffUL;
|
|
char *p = NULL;
|
|
char *l = NULL;
|
|
|
|
if (cmd == RTM_NEWADDRLABEL) {
|
|
req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
|
|
}
|
|
|
|
while (argc > 0) {
|
|
if (strcmp(*argv, "prefix") == 0) {
|
|
NEXT_ARG();
|
|
p = *argv;
|
|
get_prefix(&prefix, *argv, preferred_family);
|
|
} else if (strcmp(*argv, "dev") == 0) {
|
|
NEXT_ARG();
|
|
if ((req.ifal.ifal_index = ll_name_to_index(*argv)) == 0)
|
|
invarg("dev is invalid\n", *argv);
|
|
} else if (strcmp(*argv, "label") == 0) {
|
|
NEXT_ARG();
|
|
l = *argv;
|
|
if (get_u32(&label, *argv, 0) || label == 0xffffffffUL)
|
|
invarg("label is invalid\n", *argv);
|
|
}
|
|
argc--;
|
|
argv++;
|
|
}
|
|
if (p == NULL) {
|
|
fprintf(stderr, "Not enough information: \"prefix\" argument is required.\n");
|
|
return -1;
|
|
}
|
|
if (l == NULL) {
|
|
fprintf(stderr, "Not enough information: \"label\" argument is required.\n");
|
|
return -1;
|
|
}
|
|
addattr32(&req.n, sizeof(req), IFAL_LABEL, label);
|
|
addattr_l(&req.n, sizeof(req), IFAL_ADDRESS, &prefix.data, prefix.bytelen);
|
|
req.ifal.ifal_prefixlen = prefix.bitlen;
|
|
|
|
if (req.ifal.ifal_family == AF_UNSPEC)
|
|
req.ifal.ifal_family = AF_INET6;
|
|
|
|
if (rtnl_talk(&rth, &req.n, NULL) < 0)
|
|
return -2;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int flush_addrlabel(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
|
|
{
|
|
struct rtnl_handle rth2;
|
|
struct rtmsg *r = NLMSG_DATA(n);
|
|
int len = n->nlmsg_len;
|
|
struct rtattr *tb[IFAL_MAX+1];
|
|
|
|
len -= NLMSG_LENGTH(sizeof(*r));
|
|
if (len < 0)
|
|
return -1;
|
|
|
|
parse_rtattr(tb, IFAL_MAX, RTM_RTA(r), len);
|
|
|
|
if (tb[IFAL_ADDRESS]) {
|
|
n->nlmsg_type = RTM_DELADDRLABEL;
|
|
n->nlmsg_flags = NLM_F_REQUEST;
|
|
|
|
if (rtnl_open(&rth2, 0) < 0)
|
|
return -1;
|
|
|
|
if (rtnl_talk(&rth2, n, NULL) < 0)
|
|
return -2;
|
|
|
|
rtnl_close(&rth2);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ipaddrlabel_flush(int argc, char **argv)
|
|
{
|
|
int af = preferred_family;
|
|
|
|
if (af == AF_UNSPEC)
|
|
af = AF_INET6;
|
|
|
|
if (argc > 0) {
|
|
fprintf(stderr, "\"ip addrlabel flush\" does not allow extra arguments\n");
|
|
return -1;
|
|
}
|
|
|
|
if (rtnl_wilddump_request(&rth, af, RTM_GETADDRLABEL) < 0) {
|
|
perror("Cannot send dump request");
|
|
return -1;
|
|
}
|
|
|
|
if (rtnl_dump_filter(&rth, flush_addrlabel, NULL) < 0) {
|
|
fprintf(stderr, "Flush terminated\n");
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int do_ipaddrlabel(int argc, char **argv)
|
|
{
|
|
if (argc < 1) {
|
|
return ipaddrlabel_list(0, NULL);
|
|
} else if (matches(argv[0], "list") == 0 ||
|
|
matches(argv[0], "lst") == 0 ||
|
|
matches(argv[0], "show") == 0) {
|
|
return ipaddrlabel_list(argc-1, argv+1);
|
|
} else if (matches(argv[0], "add") == 0) {
|
|
return ipaddrlabel_modify(RTM_NEWADDRLABEL, argc-1, argv+1);
|
|
} else if (matches(argv[0], "delete") == 0) {
|
|
return ipaddrlabel_modify(RTM_DELADDRLABEL, argc-1, argv+1);
|
|
} else if (matches(argv[0], "flush") == 0) {
|
|
return ipaddrlabel_flush(argc-1, argv+1);
|
|
} else if (matches(argv[0], "help") == 0)
|
|
usage();
|
|
|
|
fprintf(stderr, "Command \"%s\" is unknown, try \"ip addrlabel help\".\n", *argv);
|
|
exit(-1);
|
|
}
|