Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Author: Justin Iurman (justin.iurman@uliege.be)
0004  *
0005  * IOAM tester for IPv6, see ioam6.sh for details on each test case.
0006  */
0007 #include <arpa/inet.h>
0008 #include <errno.h>
0009 #include <limits.h>
0010 #include <linux/const.h>
0011 #include <linux/if_ether.h>
0012 #include <linux/ioam6.h>
0013 #include <linux/ipv6.h>
0014 #include <stdlib.h>
0015 #include <string.h>
0016 #include <unistd.h>
0017 
0018 struct ioam_config {
0019     __u32 id;
0020     __u64 wide;
0021     __u16 ingr_id;
0022     __u16 egr_id;
0023     __u32 ingr_wide;
0024     __u32 egr_wide;
0025     __u32 ns_data;
0026     __u64 ns_wide;
0027     __u32 sc_id;
0028     __u8 hlim;
0029     char *sc_data;
0030 };
0031 
0032 /*
0033  * Be careful if you modify structs below - everything MUST be kept synchronized
0034  * with configurations inside ioam6.sh and always reflect the same.
0035  */
0036 
0037 static struct ioam_config node1 = {
0038     .id = 1,
0039     .wide = 11111111,
0040     .ingr_id = 0xffff, /* default value */
0041     .egr_id = 101,
0042     .ingr_wide = 0xffffffff, /* default value */
0043     .egr_wide = 101101,
0044     .ns_data = 0xdeadbee0,
0045     .ns_wide = 0xcafec0caf00dc0de,
0046     .sc_id = 777,
0047     .sc_data = "something that will be 4n-aligned",
0048     .hlim = 64,
0049 };
0050 
0051 static struct ioam_config node2 = {
0052     .id = 2,
0053     .wide = 22222222,
0054     .ingr_id = 201,
0055     .egr_id = 202,
0056     .ingr_wide = 201201,
0057     .egr_wide = 202202,
0058     .ns_data = 0xdeadbee1,
0059     .ns_wide = 0xcafec0caf11dc0de,
0060     .sc_id = 666,
0061     .sc_data = "Hello there -Obi",
0062     .hlim = 63,
0063 };
0064 
0065 static struct ioam_config node3 = {
0066     .id = 3,
0067     .wide = 33333333,
0068     .ingr_id = 301,
0069     .egr_id = 0xffff, /* default value */
0070     .ingr_wide = 301301,
0071     .egr_wide = 0xffffffff, /* default value */
0072     .ns_data = 0xdeadbee2,
0073     .ns_wide = 0xcafec0caf22dc0de,
0074     .sc_id = 0xffffff, /* default value */
0075     .sc_data = NULL,
0076     .hlim = 62,
0077 };
0078 
0079 enum {
0080     /**********
0081      * OUTPUT *
0082      **********/
0083     TEST_OUT_UNDEF_NS,
0084     TEST_OUT_NO_ROOM,
0085     TEST_OUT_BIT0,
0086     TEST_OUT_BIT1,
0087     TEST_OUT_BIT2,
0088     TEST_OUT_BIT3,
0089     TEST_OUT_BIT4,
0090     TEST_OUT_BIT5,
0091     TEST_OUT_BIT6,
0092     TEST_OUT_BIT7,
0093     TEST_OUT_BIT8,
0094     TEST_OUT_BIT9,
0095     TEST_OUT_BIT10,
0096     TEST_OUT_BIT11,
0097     TEST_OUT_BIT22,
0098     TEST_OUT_FULL_SUPP_TRACE,
0099 
0100     /*********
0101      * INPUT *
0102      *********/
0103     TEST_IN_UNDEF_NS,
0104     TEST_IN_NO_ROOM,
0105     TEST_IN_OFLAG,
0106     TEST_IN_BIT0,
0107     TEST_IN_BIT1,
0108     TEST_IN_BIT2,
0109     TEST_IN_BIT3,
0110     TEST_IN_BIT4,
0111     TEST_IN_BIT5,
0112     TEST_IN_BIT6,
0113     TEST_IN_BIT7,
0114     TEST_IN_BIT8,
0115     TEST_IN_BIT9,
0116     TEST_IN_BIT10,
0117     TEST_IN_BIT11,
0118     TEST_IN_BIT22,
0119     TEST_IN_FULL_SUPP_TRACE,
0120 
0121     /**********
0122      * GLOBAL *
0123      **********/
0124     TEST_FWD_FULL_SUPP_TRACE,
0125 
0126     __TEST_MAX,
0127 };
0128 
0129 static int check_ioam_header(int tid, struct ioam6_trace_hdr *ioam6h,
0130                  __u32 trace_type, __u16 ioam_ns)
0131 {
0132     if (__be16_to_cpu(ioam6h->namespace_id) != ioam_ns ||
0133         __be32_to_cpu(ioam6h->type_be32) != (trace_type << 8))
0134         return 1;
0135 
0136     switch (tid) {
0137     case TEST_OUT_UNDEF_NS:
0138     case TEST_IN_UNDEF_NS:
0139         return ioam6h->overflow ||
0140                ioam6h->nodelen != 1 ||
0141                ioam6h->remlen != 1;
0142 
0143     case TEST_OUT_NO_ROOM:
0144     case TEST_IN_NO_ROOM:
0145     case TEST_IN_OFLAG:
0146         return !ioam6h->overflow ||
0147                ioam6h->nodelen != 2 ||
0148                ioam6h->remlen != 1;
0149 
0150     case TEST_OUT_BIT0:
0151     case TEST_IN_BIT0:
0152     case TEST_OUT_BIT1:
0153     case TEST_IN_BIT1:
0154     case TEST_OUT_BIT2:
0155     case TEST_IN_BIT2:
0156     case TEST_OUT_BIT3:
0157     case TEST_IN_BIT3:
0158     case TEST_OUT_BIT4:
0159     case TEST_IN_BIT4:
0160     case TEST_OUT_BIT5:
0161     case TEST_IN_BIT5:
0162     case TEST_OUT_BIT6:
0163     case TEST_IN_BIT6:
0164     case TEST_OUT_BIT7:
0165     case TEST_IN_BIT7:
0166     case TEST_OUT_BIT11:
0167     case TEST_IN_BIT11:
0168         return ioam6h->overflow ||
0169                ioam6h->nodelen != 1 ||
0170                ioam6h->remlen;
0171 
0172     case TEST_OUT_BIT8:
0173     case TEST_IN_BIT8:
0174     case TEST_OUT_BIT9:
0175     case TEST_IN_BIT9:
0176     case TEST_OUT_BIT10:
0177     case TEST_IN_BIT10:
0178         return ioam6h->overflow ||
0179                ioam6h->nodelen != 2 ||
0180                ioam6h->remlen;
0181 
0182     case TEST_OUT_BIT22:
0183     case TEST_IN_BIT22:
0184         return ioam6h->overflow ||
0185                ioam6h->nodelen ||
0186                ioam6h->remlen;
0187 
0188     case TEST_OUT_FULL_SUPP_TRACE:
0189     case TEST_IN_FULL_SUPP_TRACE:
0190     case TEST_FWD_FULL_SUPP_TRACE:
0191         return ioam6h->overflow ||
0192                ioam6h->nodelen != 15 ||
0193                ioam6h->remlen;
0194 
0195     default:
0196         break;
0197     }
0198 
0199     return 1;
0200 }
0201 
0202 static int check_ioam6_data(__u8 **p, struct ioam6_trace_hdr *ioam6h,
0203                 const struct ioam_config cnf)
0204 {
0205     unsigned int len;
0206     __u8 aligned;
0207     __u64 raw64;
0208     __u32 raw32;
0209 
0210     if (ioam6h->type.bit0) {
0211         raw32 = __be32_to_cpu(*((__u32 *)*p));
0212         if (cnf.hlim != (raw32 >> 24) || cnf.id != (raw32 & 0xffffff))
0213             return 1;
0214         *p += sizeof(__u32);
0215     }
0216 
0217     if (ioam6h->type.bit1) {
0218         raw32 = __be32_to_cpu(*((__u32 *)*p));
0219         if (cnf.ingr_id != (raw32 >> 16) ||
0220             cnf.egr_id != (raw32 & 0xffff))
0221             return 1;
0222         *p += sizeof(__u32);
0223     }
0224 
0225     if (ioam6h->type.bit2)
0226         *p += sizeof(__u32);
0227 
0228     if (ioam6h->type.bit3)
0229         *p += sizeof(__u32);
0230 
0231     if (ioam6h->type.bit4) {
0232         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0233             return 1;
0234         *p += sizeof(__u32);
0235     }
0236 
0237     if (ioam6h->type.bit5) {
0238         if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ns_data)
0239             return 1;
0240         *p += sizeof(__u32);
0241     }
0242 
0243     if (ioam6h->type.bit6)
0244         *p += sizeof(__u32);
0245 
0246     if (ioam6h->type.bit7) {
0247         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0248             return 1;
0249         *p += sizeof(__u32);
0250     }
0251 
0252     if (ioam6h->type.bit8) {
0253         raw64 = __be64_to_cpu(*((__u64 *)*p));
0254         if (cnf.hlim != (raw64 >> 56) ||
0255             cnf.wide != (raw64 & 0xffffffffffffff))
0256             return 1;
0257         *p += sizeof(__u64);
0258     }
0259 
0260     if (ioam6h->type.bit9) {
0261         if (__be32_to_cpu(*((__u32 *)*p)) != cnf.ingr_wide)
0262             return 1;
0263         *p += sizeof(__u32);
0264 
0265         if (__be32_to_cpu(*((__u32 *)*p)) != cnf.egr_wide)
0266             return 1;
0267         *p += sizeof(__u32);
0268     }
0269 
0270     if (ioam6h->type.bit10) {
0271         if (__be64_to_cpu(*((__u64 *)*p)) != cnf.ns_wide)
0272             return 1;
0273         *p += sizeof(__u64);
0274     }
0275 
0276     if (ioam6h->type.bit11) {
0277         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0278             return 1;
0279         *p += sizeof(__u32);
0280     }
0281 
0282     if (ioam6h->type.bit12) {
0283         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0284             return 1;
0285         *p += sizeof(__u32);
0286     }
0287 
0288     if (ioam6h->type.bit13) {
0289         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0290             return 1;
0291         *p += sizeof(__u32);
0292     }
0293 
0294     if (ioam6h->type.bit14) {
0295         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0296             return 1;
0297         *p += sizeof(__u32);
0298     }
0299 
0300     if (ioam6h->type.bit15) {
0301         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0302             return 1;
0303         *p += sizeof(__u32);
0304     }
0305 
0306     if (ioam6h->type.bit16) {
0307         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0308             return 1;
0309         *p += sizeof(__u32);
0310     }
0311 
0312     if (ioam6h->type.bit17) {
0313         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0314             return 1;
0315         *p += sizeof(__u32);
0316     }
0317 
0318     if (ioam6h->type.bit18) {
0319         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0320             return 1;
0321         *p += sizeof(__u32);
0322     }
0323 
0324     if (ioam6h->type.bit19) {
0325         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0326             return 1;
0327         *p += sizeof(__u32);
0328     }
0329 
0330     if (ioam6h->type.bit20) {
0331         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0332             return 1;
0333         *p += sizeof(__u32);
0334     }
0335 
0336     if (ioam6h->type.bit21) {
0337         if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
0338             return 1;
0339         *p += sizeof(__u32);
0340     }
0341 
0342     if (ioam6h->type.bit22) {
0343         len = cnf.sc_data ? strlen(cnf.sc_data) : 0;
0344         aligned = cnf.sc_data ? __ALIGN_KERNEL(len, 4) : 0;
0345 
0346         raw32 = __be32_to_cpu(*((__u32 *)*p));
0347         if (aligned != (raw32 >> 24) * 4 ||
0348             cnf.sc_id != (raw32 & 0xffffff))
0349             return 1;
0350         *p += sizeof(__u32);
0351 
0352         if (cnf.sc_data) {
0353             if (strncmp((char *)*p, cnf.sc_data, len))
0354                 return 1;
0355 
0356             *p += len;
0357             aligned -= len;
0358 
0359             while (aligned--) {
0360                 if (**p != '\0')
0361                     return 1;
0362                 *p += sizeof(__u8);
0363             }
0364         }
0365     }
0366 
0367     return 0;
0368 }
0369 
0370 static int check_ioam_header_and_data(int tid, struct ioam6_trace_hdr *ioam6h,
0371                       __u32 trace_type, __u16 ioam_ns)
0372 {
0373     __u8 *p;
0374 
0375     if (check_ioam_header(tid, ioam6h, trace_type, ioam_ns))
0376         return 1;
0377 
0378     p = ioam6h->data + ioam6h->remlen * 4;
0379 
0380     switch (tid) {
0381     case TEST_OUT_BIT0:
0382     case TEST_OUT_BIT1:
0383     case TEST_OUT_BIT2:
0384     case TEST_OUT_BIT3:
0385     case TEST_OUT_BIT4:
0386     case TEST_OUT_BIT5:
0387     case TEST_OUT_BIT6:
0388     case TEST_OUT_BIT7:
0389     case TEST_OUT_BIT8:
0390     case TEST_OUT_BIT9:
0391     case TEST_OUT_BIT10:
0392     case TEST_OUT_BIT11:
0393     case TEST_OUT_BIT22:
0394     case TEST_OUT_FULL_SUPP_TRACE:
0395         return check_ioam6_data(&p, ioam6h, node1);
0396 
0397     case TEST_IN_BIT0:
0398     case TEST_IN_BIT1:
0399     case TEST_IN_BIT2:
0400     case TEST_IN_BIT3:
0401     case TEST_IN_BIT4:
0402     case TEST_IN_BIT5:
0403     case TEST_IN_BIT6:
0404     case TEST_IN_BIT7:
0405     case TEST_IN_BIT8:
0406     case TEST_IN_BIT9:
0407     case TEST_IN_BIT10:
0408     case TEST_IN_BIT11:
0409     case TEST_IN_BIT22:
0410     case TEST_IN_FULL_SUPP_TRACE:
0411     {
0412         __u32 tmp32 = node2.egr_wide;
0413         __u16 tmp16 = node2.egr_id;
0414         int res;
0415 
0416         node2.egr_id = 0xffff;
0417         node2.egr_wide = 0xffffffff;
0418 
0419         res = check_ioam6_data(&p, ioam6h, node2);
0420 
0421         node2.egr_id = tmp16;
0422         node2.egr_wide = tmp32;
0423 
0424         return res;
0425     }
0426 
0427     case TEST_FWD_FULL_SUPP_TRACE:
0428         if (check_ioam6_data(&p, ioam6h, node3))
0429             return 1;
0430         if (check_ioam6_data(&p, ioam6h, node2))
0431             return 1;
0432         return check_ioam6_data(&p, ioam6h, node1);
0433 
0434     default:
0435         break;
0436     }
0437 
0438     return 1;
0439 }
0440 
0441 static int str2id(const char *tname)
0442 {
0443     if (!strcmp("out_undef_ns", tname))
0444         return TEST_OUT_UNDEF_NS;
0445     if (!strcmp("out_no_room", tname))
0446         return TEST_OUT_NO_ROOM;
0447     if (!strcmp("out_bit0", tname))
0448         return TEST_OUT_BIT0;
0449     if (!strcmp("out_bit1", tname))
0450         return TEST_OUT_BIT1;
0451     if (!strcmp("out_bit2", tname))
0452         return TEST_OUT_BIT2;
0453     if (!strcmp("out_bit3", tname))
0454         return TEST_OUT_BIT3;
0455     if (!strcmp("out_bit4", tname))
0456         return TEST_OUT_BIT4;
0457     if (!strcmp("out_bit5", tname))
0458         return TEST_OUT_BIT5;
0459     if (!strcmp("out_bit6", tname))
0460         return TEST_OUT_BIT6;
0461     if (!strcmp("out_bit7", tname))
0462         return TEST_OUT_BIT7;
0463     if (!strcmp("out_bit8", tname))
0464         return TEST_OUT_BIT8;
0465     if (!strcmp("out_bit9", tname))
0466         return TEST_OUT_BIT9;
0467     if (!strcmp("out_bit10", tname))
0468         return TEST_OUT_BIT10;
0469     if (!strcmp("out_bit11", tname))
0470         return TEST_OUT_BIT11;
0471     if (!strcmp("out_bit22", tname))
0472         return TEST_OUT_BIT22;
0473     if (!strcmp("out_full_supp_trace", tname))
0474         return TEST_OUT_FULL_SUPP_TRACE;
0475     if (!strcmp("in_undef_ns", tname))
0476         return TEST_IN_UNDEF_NS;
0477     if (!strcmp("in_no_room", tname))
0478         return TEST_IN_NO_ROOM;
0479     if (!strcmp("in_oflag", tname))
0480         return TEST_IN_OFLAG;
0481     if (!strcmp("in_bit0", tname))
0482         return TEST_IN_BIT0;
0483     if (!strcmp("in_bit1", tname))
0484         return TEST_IN_BIT1;
0485     if (!strcmp("in_bit2", tname))
0486         return TEST_IN_BIT2;
0487     if (!strcmp("in_bit3", tname))
0488         return TEST_IN_BIT3;
0489     if (!strcmp("in_bit4", tname))
0490         return TEST_IN_BIT4;
0491     if (!strcmp("in_bit5", tname))
0492         return TEST_IN_BIT5;
0493     if (!strcmp("in_bit6", tname))
0494         return TEST_IN_BIT6;
0495     if (!strcmp("in_bit7", tname))
0496         return TEST_IN_BIT7;
0497     if (!strcmp("in_bit8", tname))
0498         return TEST_IN_BIT8;
0499     if (!strcmp("in_bit9", tname))
0500         return TEST_IN_BIT9;
0501     if (!strcmp("in_bit10", tname))
0502         return TEST_IN_BIT10;
0503     if (!strcmp("in_bit11", tname))
0504         return TEST_IN_BIT11;
0505     if (!strcmp("in_bit22", tname))
0506         return TEST_IN_BIT22;
0507     if (!strcmp("in_full_supp_trace", tname))
0508         return TEST_IN_FULL_SUPP_TRACE;
0509     if (!strcmp("fwd_full_supp_trace", tname))
0510         return TEST_FWD_FULL_SUPP_TRACE;
0511 
0512     return -1;
0513 }
0514 
0515 static int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2)
0516 {
0517     return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) |
0518         (a1->s6_addr32[1] ^ a2->s6_addr32[1]) |
0519         (a1->s6_addr32[2] ^ a2->s6_addr32[2]) |
0520         (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0;
0521 }
0522 
0523 static int get_u32(__u32 *val, const char *arg, int base)
0524 {
0525     unsigned long res;
0526     char *ptr;
0527 
0528     if (!arg || !*arg)
0529         return -1;
0530     res = strtoul(arg, &ptr, base);
0531 
0532     if (!ptr || ptr == arg || *ptr)
0533         return -1;
0534 
0535     if (res == ULONG_MAX && errno == ERANGE)
0536         return -1;
0537 
0538     if (res > 0xFFFFFFFFUL)
0539         return -1;
0540 
0541     *val = res;
0542     return 0;
0543 }
0544 
0545 static int get_u16(__u16 *val, const char *arg, int base)
0546 {
0547     unsigned long res;
0548     char *ptr;
0549 
0550     if (!arg || !*arg)
0551         return -1;
0552     res = strtoul(arg, &ptr, base);
0553 
0554     if (!ptr || ptr == arg || *ptr)
0555         return -1;
0556 
0557     if (res == ULONG_MAX && errno == ERANGE)
0558         return -1;
0559 
0560     if (res > 0xFFFFUL)
0561         return -1;
0562 
0563     *val = res;
0564     return 0;
0565 }
0566 
0567 static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = {
0568     [TEST_OUT_UNDEF_NS]     = check_ioam_header,
0569     [TEST_OUT_NO_ROOM]      = check_ioam_header,
0570     [TEST_OUT_BIT0]     = check_ioam_header_and_data,
0571     [TEST_OUT_BIT1]     = check_ioam_header_and_data,
0572     [TEST_OUT_BIT2]     = check_ioam_header_and_data,
0573     [TEST_OUT_BIT3]     = check_ioam_header_and_data,
0574     [TEST_OUT_BIT4]     = check_ioam_header_and_data,
0575     [TEST_OUT_BIT5]     = check_ioam_header_and_data,
0576     [TEST_OUT_BIT6]     = check_ioam_header_and_data,
0577     [TEST_OUT_BIT7]     = check_ioam_header_and_data,
0578     [TEST_OUT_BIT8]     = check_ioam_header_and_data,
0579     [TEST_OUT_BIT9]     = check_ioam_header_and_data,
0580     [TEST_OUT_BIT10]        = check_ioam_header_and_data,
0581     [TEST_OUT_BIT11]        = check_ioam_header_and_data,
0582     [TEST_OUT_BIT22]        = check_ioam_header_and_data,
0583     [TEST_OUT_FULL_SUPP_TRACE]  = check_ioam_header_and_data,
0584     [TEST_IN_UNDEF_NS]      = check_ioam_header,
0585     [TEST_IN_NO_ROOM]       = check_ioam_header,
0586     [TEST_IN_OFLAG]     = check_ioam_header,
0587     [TEST_IN_BIT0]          = check_ioam_header_and_data,
0588     [TEST_IN_BIT1]          = check_ioam_header_and_data,
0589     [TEST_IN_BIT2]          = check_ioam_header_and_data,
0590     [TEST_IN_BIT3]          = check_ioam_header_and_data,
0591     [TEST_IN_BIT4]          = check_ioam_header_and_data,
0592     [TEST_IN_BIT5]          = check_ioam_header_and_data,
0593     [TEST_IN_BIT6]          = check_ioam_header_and_data,
0594     [TEST_IN_BIT7]          = check_ioam_header_and_data,
0595     [TEST_IN_BIT8]          = check_ioam_header_and_data,
0596     [TEST_IN_BIT9]          = check_ioam_header_and_data,
0597     [TEST_IN_BIT10]     = check_ioam_header_and_data,
0598     [TEST_IN_BIT11]     = check_ioam_header_and_data,
0599     [TEST_IN_BIT22]     = check_ioam_header_and_data,
0600     [TEST_IN_FULL_SUPP_TRACE]   = check_ioam_header_and_data,
0601     [TEST_FWD_FULL_SUPP_TRACE]  = check_ioam_header_and_data,
0602 };
0603 
0604 int main(int argc, char **argv)
0605 {
0606     int fd, size, hoplen, tid, ret = 1;
0607     struct in6_addr src, dst;
0608     struct ioam6_hdr *opt;
0609     struct ipv6hdr *ip6h;
0610     __u8 buffer[400], *p;
0611     __u16 ioam_ns;
0612     __u32 tr_type;
0613 
0614     if (argc != 7)
0615         goto out;
0616 
0617     tid = str2id(argv[2]);
0618     if (tid < 0 || !func[tid])
0619         goto out;
0620 
0621     if (inet_pton(AF_INET6, argv[3], &src) != 1 ||
0622         inet_pton(AF_INET6, argv[4], &dst) != 1)
0623         goto out;
0624 
0625     if (get_u32(&tr_type, argv[5], 16) ||
0626         get_u16(&ioam_ns, argv[6], 0))
0627         goto out;
0628 
0629     fd = socket(AF_PACKET, SOCK_DGRAM, __cpu_to_be16(ETH_P_IPV6));
0630     if (!fd)
0631         goto out;
0632 
0633     if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE,
0634                argv[1], strlen(argv[1])))
0635         goto close;
0636 
0637 recv:
0638     size = recv(fd, buffer, sizeof(buffer), 0);
0639     if (size <= 0)
0640         goto close;
0641 
0642     ip6h = (struct ipv6hdr *)buffer;
0643 
0644     if (!ipv6_addr_equal(&ip6h->saddr, &src) ||
0645         !ipv6_addr_equal(&ip6h->daddr, &dst))
0646         goto recv;
0647 
0648     if (ip6h->nexthdr != IPPROTO_HOPOPTS)
0649         goto close;
0650 
0651     p = buffer + sizeof(*ip6h);
0652     hoplen = (p[1] + 1) << 3;
0653     p += sizeof(struct ipv6_hopopt_hdr);
0654 
0655     while (hoplen > 0) {
0656         opt = (struct ioam6_hdr *)p;
0657 
0658         if (opt->opt_type == IPV6_TLV_IOAM &&
0659             opt->type == IOAM6_TYPE_PREALLOC) {
0660             p += sizeof(*opt);
0661             ret = func[tid](tid, (struct ioam6_trace_hdr *)p,
0662                        tr_type, ioam_ns);
0663             break;
0664         }
0665 
0666         p += opt->opt_len + 2;
0667         hoplen -= opt->opt_len + 2;
0668     }
0669 close:
0670     close(fd);
0671 out:
0672     return ret;
0673 }