This patch adds two helper functions to print and parse Segment Routing Headers.
Signed-off-by: David Lebrun <david.leb...@uclouvain.be> --- ip/iproute_lwtunnel.c | 124 +++++++++++++++++++++++++++++--------------------- 1 file changed, 72 insertions(+), 52 deletions(-) diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c index 5c0c7d1..16d2584 100644 --- a/ip/iproute_lwtunnel.c +++ b/ip/iproute_lwtunnel.c @@ -83,24 +83,10 @@ static int read_encap_type(const char *name) return LWTUNNEL_ENCAP_NONE; } -static void print_encap_seg6(FILE *fp, struct rtattr *encap) +static void print_srh(FILE *fp, struct ipv6_sr_hdr *srh) { - struct rtattr *tb[SEG6_IPTUNNEL_MAX+1]; - struct seg6_iptunnel_encap *tuninfo; - struct ipv6_sr_hdr *srh; int i; - parse_rtattr_nested(tb, SEG6_IPTUNNEL_MAX, encap); - - if (!tb[SEG6_IPTUNNEL_SRH]) - return; - - tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]); - fprintf(fp, "mode %s ", - (tuninfo->mode == SEG6_IPTUN_MODE_ENCAP) ? "encap" : "inline"); - - srh = tuninfo->srh; - fprintf(fp, "segs %d [ ", srh->first_segment + 1); for (i = srh->first_segment; i >= 0; i--) @@ -118,6 +104,23 @@ static void print_encap_seg6(FILE *fp, struct rtattr *encap) } } +static void print_encap_seg6(FILE *fp, struct rtattr *encap) +{ + struct rtattr *tb[SEG6_IPTUNNEL_MAX+1]; + struct seg6_iptunnel_encap *tuninfo; + + parse_rtattr_nested(tb, SEG6_IPTUNNEL_MAX, encap); + + if (!tb[SEG6_IPTUNNEL_SRH]) + return; + + tuninfo = RTA_DATA(tb[SEG6_IPTUNNEL_SRH]); + fprintf(fp, "mode %s ", + (tuninfo->mode == SEG6_IPTUN_MODE_ENCAP) ? "encap" : "inline"); + + print_srh(fp, tuninfo->srh); +} + static void print_encap_mpls(FILE *fp, struct rtattr *encap) { struct rtattr *tb[MPLS_IPTUNNEL_MAX+1]; @@ -290,6 +293,55 @@ void lwt_print_encap(FILE *fp, struct rtattr *encap_type, } } +static struct ipv6_sr_hdr *parse_srh(char *segbuf, int hmac, bool encap) +{ + struct ipv6_sr_hdr *srh; + int nsegs = 0; + int srhlen; + char *s; + int i; + + s = segbuf; + for (i = 0; *s; *s++ == ',' ? i++ : *s); + nsegs = i + 1; + + if (!encap) + nsegs++; + + srhlen = 8 + 16*nsegs; + + if (hmac) + srhlen += 40; + + srh = malloc(srhlen); + memset(srh, 0, srhlen); + + srh->hdrlen = (srhlen >> 3) - 1; + srh->type = 4; + srh->segments_left = nsegs - 1; + srh->first_segment = nsegs - 1; + + if (hmac) + srh->flags |= SR6_FLAG1_HMAC; + + i = srh->first_segment; + for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) { + inet_get_addr(s, NULL, &srh->segments[i]); + i--; + } + + if (hmac) { + struct sr6_tlv_hmac *tlv; + + tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40); + tlv->tlvhdr.type = SR6_TLV_HMAC; + tlv->tlvhdr.len = 38; + tlv->hmackeyid = htonl(hmac); + } + + return srh; +} + static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, char ***argvp) { @@ -301,10 +353,7 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, int argc = *argcp; int encap = -1; __u32 hmac = 0; - int nsegs = 0; int srhlen; - char *s; - int i; while (argc > 0) { if (strcmp(*argv, "mode") == 0) { @@ -338,17 +387,8 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, argc--; argv++; } - s = segbuf; - for (i = 0; *s; *s++ == ',' ? i++ : *s); - nsegs = i + 1; - - if (!encap) - nsegs++; - - srhlen = 8 + 16*nsegs; - - if (hmac) - srhlen += 40; + srh = parse_srh(segbuf, hmac, encap); + srhlen = (srh->hdrlen + 1) << 3; tuninfo = malloc(sizeof(*tuninfo) + srhlen); memset(tuninfo, 0, sizeof(*tuninfo) + srhlen); @@ -358,33 +398,13 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp, else tuninfo->mode = SEG6_IPTUN_MODE_INLINE; - srh = tuninfo->srh; - srh->hdrlen = (srhlen >> 3) - 1; - srh->type = 4; - srh->segments_left = nsegs - 1; - srh->first_segment = nsegs - 1; - - if (hmac) - srh->flags |= SR6_FLAG1_HMAC; - - i = srh->first_segment; - for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) { - inet_get_addr(s, NULL, &srh->segments[i]); - i--; - } - - if (hmac) { - struct sr6_tlv_hmac *tlv; - - tlv = (struct sr6_tlv_hmac *)((char *)srh + srhlen - 40); - tlv->tlvhdr.type = SR6_TLV_HMAC; - tlv->tlvhdr.len = 38; - tlv->hmackeyid = htonl(hmac); - } + memcpy(tuninfo->srh, srh, srhlen); rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo, sizeof(*tuninfo) + srhlen); + free(tuninfo); + free(srh); *argcp = argc + 1; *argvp = argv - 1; -- 2.10.2