On Tue, Jan 10, 2017 at 8:41 AM, David Lebrun <david.leb...@uclouvain.be> wrote: > This patch add commands to support the tunnel source properties > ("ip sr tunsrc") and the HMAC key -> secret, algorithm binding > ("ip sr hmac"). > > Signed-off-by: David Lebrun <david.leb...@uclouvain.be> > --- > ip/Makefile | 2 +- > ip/ip.c | 3 +- > ip/ip_common.h | 1 + > ip/ipseg6.c | 238 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 242 insertions(+), 2 deletions(-) > create mode 100644 ip/ipseg6.c > > diff --git a/ip/Makefile b/ip/Makefile > index 1928489..678a795 100644 > --- a/ip/Makefile > +++ b/ip/Makefile > @@ -8,7 +8,7 @@ IPOBJ=ip.o ipaddress.o ipaddrlabel.o iproute.o iprule.o > ipnetns.o \ > link_iptnl.o link_gre6.o iplink_bond.o iplink_bond_slave.o iplink_hsr.o \ > iplink_bridge.o iplink_bridge_slave.o ipfou.o iplink_ipvlan.o \ > iplink_geneve.o iplink_vrf.o iproute_lwtunnel.o ipmacsec.o ipila.o \ > - ipvrf.o > + ipvrf.o ipseg6.o > > RTMONOBJ=rtmon.o > > diff --git a/ip/ip.c b/ip/ip.c > index 07050b0..7c14a8e 100644 > --- a/ip/ip.c > +++ b/ip/ip.c > @@ -52,7 +52,7 @@ static void usage(void) > "where OBJECT := { link | address | addrlabel | route | rule | neigh | > ntable |\n" > " tunnel | tuntap | maddress | mroute | mrule | monitor | > xfrm |\n" > " netns | l2tp | fou | macsec | tcp_metrics | token | > netconf | ila |\n" > -" vrf }\n" > +" vrf | sr }\n" > " OPTIONS := { -V[ersion] | -s[tatistics] | -d[etails] | -r[esolve] > |\n" > " -h[uman-readable] | -iec |\n" > " -f[amily] { inet | inet6 | ipx | dnet | mpls | bridge | > link } |\n" > @@ -101,6 +101,7 @@ static const struct cmd { > { "netns", do_netns }, > { "netconf", do_ipnetconf }, > { "vrf", do_ipvrf}, > + { "sr", do_seg6 }, > { "help", do_help }, > { 0 } > }; > diff --git a/ip/ip_common.h b/ip/ip_common.h > index ab6a834..13108c6 100644 > --- a/ip/ip_common.h > +++ b/ip/ip_common.h > @@ -59,6 +59,7 @@ int do_ipnetconf(int argc, char **argv); > int do_iptoken(int argc, char **argv); > int do_ipvrf(int argc, char **argv); > void vrf_reset(void); > +int do_seg6(int argc, char **argv); > > int iplink_get(unsigned int flags, char *name, __u32 filt_mask); > > diff --git a/ip/ipseg6.c b/ip/ipseg6.c > new file mode 100644 > index 0000000..0d4130e > --- /dev/null > +++ b/ip/ipseg6.c > @@ -0,0 +1,238 @@ > +/* > + * seg6.c "ip sr/seg6" > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License > + * version 2 as published by the Free Software Foundation; > + * > + * Author: David Lebrun <david.leb...@uclouvain.be> > + */ > + > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <sys/types.h> > +#include <sys/socket.h> > +#include <arpa/inet.h> > +#include <sys/ioctl.h> > +#include <linux/if.h> > + > +#include <linux/genetlink.h> > +#include <linux/seg6_genl.h> > +#include <linux/seg6_hmac.h> > + > +#include "utils.h" > +#include "ip_common.h" > +#include "libgenl.h" > + > +#define HMAC_KEY_PROMPT "Enter secret for HMAC key ID (blank to delete): " > + > +static void usage(void) > +{ > + fprintf(stderr, "Usage: ip sr { COMMAND | help }\n"); > + fprintf(stderr, " ip sr hmac show\n"); > + fprintf(stderr, " ip sr hmac set KEYID ALGO\n"); > + fprintf(stderr, " ip sr tunsrc show\n"); > + fprintf(stderr, " ip sr tunsrc set ADDRESS\n"); > + fprintf(stderr, "where ALGO := { sha1 | sha256 }\n"); > + exit(-1); > +} > + > +static struct rtnl_handle grth = { .fd = -1 }; > +static int genl_family = -1; > + > +#define SEG6_REQUEST(_req, _bufsiz, _cmd, _flags) \ > + GENL_REQUEST(_req, _bufsiz, genl_family, 0, \ > + SEG6_GENL_VERSION, _cmd, _flags) > + > +static struct { > + int cmd; > + struct in6_addr addr; > + __u32 keyid; > + char *pass; > + __u8 alg_id; > +} opts; > + > +static int process_msg(const struct sockaddr_nl *who, struct nlmsghdr *n, > + void *arg) > +{ > + struct rtattr *attrs[SEG6_ATTR_MAX + 1]; > + struct genlmsghdr *ghdr; > + FILE *fp = (FILE *)arg; > + int len = n->nlmsg_len; > + > + if (n->nlmsg_type != genl_family) > + return -1; > + > + len -= NLMSG_LENGTH(GENL_HDRLEN); > + if (len < 0) > + return -1; > + > + ghdr = NLMSG_DATA(n); > + > + parse_rtattr(attrs, SEG6_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len); > + > + switch (ghdr->cmd) { > + case SEG6_CMD_DUMPHMAC: > + { > + char secret[64]; > + char *algstr; > + __u8 slen = rta_getattr_u8(attrs[SEG6_ATTR_SECRETLEN]); > + __u8 alg_id = rta_getattr_u8(attrs[SEG6_ATTR_ALGID]); > + > + memset(secret, 0, 64); > + > + if (slen > 63) { > + fprintf(stderr, "HMAC secret length %d > 63, " > + "truncated\n", slen); > + slen = 63; > + } > + memcpy(secret, RTA_DATA(attrs[SEG6_ATTR_SECRET]), slen); > + > + switch (alg_id) { > + case SEG6_HMAC_ALGO_SHA1: > + algstr = "sha1"; > + break; > + case SEG6_HMAC_ALGO_SHA256: > + algstr = "sha256"; > + break; > + default: > + algstr = "<unknown>"; > + } > + > + fprintf(fp, "hmac %u ", > + rta_getattr_u32(attrs[SEG6_ATTR_HMACKEYID])); > + fprintf(fp, "algo %s ", algstr); > + fprintf(fp, "secret \"%s\" ", secret); > + > + fprintf(fp, "\n"); > + break; > + } > + case SEG6_CMD_GET_TUNSRC: > + { > + fprintf(fp, "tunsrc addr %s\n", > + rt_addr_n2a(AF_INET6, 16, > + RTA_DATA(attrs[SEG6_ATTR_DST]))); > + break; > + } > + } > + > + return 0; > +} > + > +static int seg6_do_cmd(void) > +{ > + SEG6_REQUEST(req, 1024, opts.cmd, NLM_F_REQUEST); > + int repl = 0, dump = 0; > + > + if (genl_family < 0) { > + if (rtnl_open_byproto(&grth, 0, NETLINK_GENERIC) < 0) { > + fprintf(stderr, "Cannot open generic netlink > socket\n"); > + exit(1); > + } > + genl_family = genl_resolve_family(&grth, SEG6_GENL_NAME); > + if (genl_family < 0) > + exit(1); > + req.n.nlmsg_type = genl_family; > + } > + > + switch (opts.cmd) { > + case SEG6_CMD_SETHMAC: > + { > + addattr32(&req.n, sizeof(req), SEG6_ATTR_HMACKEYID, > opts.keyid); > + addattr8(&req.n, sizeof(req), SEG6_ATTR_SECRETLEN, > + strlen(opts.pass)); > + addattr8(&req.n, sizeof(req), SEG6_ATTR_ALGID, opts.alg_id); > + if (strlen(opts.pass)) > + addattr_l(&req.n, sizeof(req), SEG6_ATTR_SECRET, > + opts.pass, strlen(opts.pass)); > + break; > + } > + case SEG6_CMD_SET_TUNSRC: > + addattr_l(&req.n, sizeof(req), SEG6_ATTR_DST, &opts.addr, > + sizeof(struct in6_addr)); > + break; > + case SEG6_CMD_DUMPHMAC: > + dump = 1; > + break; > + case SEG6_CMD_GET_TUNSRC: > + repl = 1; > + break; > + } > + > + if (!repl && !dump) { > + if (rtnl_talk(&grth, &req.n, NULL, 0) < 0) > + return -1; > + } else if (repl) { > + if (rtnl_talk(&grth, &req.n, &req.n, sizeof(req)) < 0) > + return -2; > + if (process_msg(NULL, &req.n, stdout) < 0) { > + fprintf(stderr, "Error parsing reply\n"); > + exit(1); > + } > + } else { > + req.n.nlmsg_flags |= NLM_F_DUMP; > + req.n.nlmsg_seq = grth.dump = ++grth.seq; > + if (rtnl_send(&grth, &req, req.n.nlmsg_len) < 0) { > + perror("Failed to send dump request"); > + exit(1); > + } > + > + if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) { > + fprintf(stderr, "Dump terminated\n"); > + exit(1); > + } > + } > + > + return 0; > +} > + > +int do_seg6(int argc, char **argv) > +{ > + if (argc < 1 || matches(*argv, "help") == 0) > + usage(); > + > + memset(&opts, 0, sizeof(opts)); > + > + if (matches(*argv, "hmac") == 0) { > + NEXT_ARG(); > + if (matches(*argv, "show") == 0) { > + opts.cmd = SEG6_CMD_DUMPHMAC; > + } else if (matches(*argv, "set") == 0) { > + NEXT_ARG(); > + if (get_u32(&opts.keyid, *argv, 0) || opts.keyid == 0) > + invarg("hmac KEYID value is invalid", *argv); > + NEXT_ARG(); > + if (strcmp(*argv, "sha1") == 0) { > + opts.alg_id = SEG6_HMAC_ALGO_SHA1; > + } else if (strcmp(*argv, "sha256") == 0) { > + opts.alg_id = SEG6_HMAC_ALGO_SHA256; > + } else { > + invarg("hmac ALGO value is invalid", *argv); > + } > + opts.cmd = SEG6_CMD_SETHMAC; > + opts.pass = getpass(HMAC_KEY_PROMPT); > + } else { > + invarg("unknown", *argv); > + } > + } else if (matches(*argv, "tunsrc") == 0) { > + NEXT_ARG(); > + if (matches(*argv, "show") == 0) { > + opts.cmd = SEG6_CMD_GET_TUNSRC; > + } else if (matches(*argv, "set") == 0) { > + NEXT_ARG(); > + opts.cmd = SEG6_CMD_SET_TUNSRC; > + if (!inet_get_addr(*argv, NULL, &opts.addr)) > + invarg("tunsrc ADDRESS value is invalid", > + *argv); > + } else { > + invarg("unknown", *argv); > + } > + } else { > + invarg("unknown", *argv); > + } > + > + return seg6_do_cmd(); > +} > -- > 2.7.3 >
Acked-by: Tom Herbert <t...@herbertland.com>