/* * iplink_geneve.c GENEVE device support * * 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: John W. Linville <linville@tuxdriver.com> */ #include <stdio.h> #include "rt_names.h" #include "utils.h" #include "ip_common.h" static void print_explain(FILE *f) { fprintf(f, "Usage: ... geneve id VNI remote ADDR\n"); fprintf(f, " [ ttl TTL ] [ tos TOS ]\n"); fprintf(f, "\n"); fprintf(f, "Where: VNI := 0-16777215\n"); fprintf(f, " ADDR := IP_ADDRESS\n"); fprintf(f, " TOS := { NUMBER | inherit }\n"); fprintf(f, " TTL := { 1..255 | inherit }\n"); } static void explain(void) { print_explain(stderr); } static int geneve_parse_opt(struct link_util *lu, int argc, char **argv, struct nlmsghdr *n) { __u32 vni = 0; int vni_set = 0; __u32 daddr = 0; struct in6_addr daddr6 = IN6ADDR_ANY_INIT; __u8 ttl = 0; __u8 tos = 0; while (argc > 0) { if (!matches(*argv, "id") || !matches(*argv, "vni")) { NEXT_ARG(); if (get_u32(&vni, *argv, 0) || vni >= 1u << 24) invarg("invalid id", *argv); vni_set = 1; } else if (!matches(*argv, "remote")) { NEXT_ARG(); if (!inet_get_addr(*argv, &daddr, &daddr6)) { fprintf(stderr, "Invalid address \"%s\"\n", *argv); return -1; } if (IN6_IS_ADDR_MULTICAST(&daddr6) || IN_MULTICAST(ntohl(daddr))) invarg("invalid remote address", *argv); } else if (!matches(*argv, "ttl") || !matches(*argv, "hoplimit")) { unsigned uval; NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (get_unsigned(&uval, *argv, 0)) invarg("invalid TTL", *argv); if (uval > 255) invarg("TTL must be <= 255", *argv); ttl = uval; } } else if (!matches(*argv, "tos") || !matches(*argv, "dsfield")) { __u32 uval; NEXT_ARG(); if (strcmp(*argv, "inherit") != 0) { if (rtnl_dsfield_a2n(&uval, *argv)) invarg("bad TOS value", *argv); tos = uval; } else tos = 1; } else if (matches(*argv, "help") == 0) { explain(); return -1; } else { fprintf(stderr, "geneve: unknown command \"%s\"?\n", *argv); explain(); return -1; } argc--, argv++; } if (!vni_set) { fprintf(stderr, "geneve: missing virtual network identifier\n"); return -1; } if (!daddr && memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) == 0) { fprintf(stderr, "geneve: remote link partner not specified\n"); return -1; } addattr32(n, 1024, IFLA_GENEVE_ID, vni); if (daddr) addattr_l(n, 1024, IFLA_GENEVE_REMOTE, &daddr, 4); if (memcmp(&daddr6, &in6addr_any, sizeof(daddr6)) != 0) addattr_l(n, 1024, IFLA_GENEVE_REMOTE6, &daddr6, sizeof(struct in6_addr)); addattr8(n, 1024, IFLA_GENEVE_TTL, ttl); addattr8(n, 1024, IFLA_GENEVE_TOS, tos); return 0; } static void geneve_print_opt(struct link_util *lu, FILE *f, struct rtattr *tb[]) { __u32 vni; char s1[1024]; __u8 tos; if (!tb) return; if (!tb[IFLA_GENEVE_ID] || RTA_PAYLOAD(tb[IFLA_GENEVE_ID]) < sizeof(__u32)) return; vni = rta_getattr_u32(tb[IFLA_GENEVE_ID]); fprintf(f, "id %u ", vni); if (tb[IFLA_GENEVE_REMOTE]) { __be32 addr = rta_getattr_u32(tb[IFLA_GENEVE_REMOTE]); if (addr) fprintf(f, "remote %s ", format_host(AF_INET, 4, &addr, s1, sizeof(s1))); } else if (tb[IFLA_GENEVE_REMOTE6]) { struct in6_addr addr; memcpy(&addr, RTA_DATA(tb[IFLA_GENEVE_REMOTE6]), sizeof(struct in6_addr)); if (memcmp(&addr, &in6addr_any, sizeof(addr)) != 0) { if (IN6_IS_ADDR_MULTICAST(&addr)) fprintf(f, "remote %s ", format_host(AF_INET6, sizeof(struct in6_addr), &addr, s1, sizeof(s1))); } } if (tb[IFLA_GENEVE_TTL]) { __u8 ttl = rta_getattr_u8(tb[IFLA_GENEVE_TTL]); if (ttl) fprintf(f, "ttl %d ", ttl); } if (tb[IFLA_GENEVE_TOS] && (tos = rta_getattr_u8(tb[IFLA_GENEVE_TOS]))) { if (tos == 1) fprintf(f, "tos inherit "); else fprintf(f, "tos %#x ", tos); } } static void geneve_print_help(struct link_util *lu, int argc, char **argv, FILE *f) { print_explain(f); } struct link_util geneve_link_util = { .id = "geneve", .maxattr = IFLA_GENEVE_MAX, .parse_opt = geneve_parse_opt, .print_opt = geneve_print_opt, .print_help = geneve_print_help, };