github.com/vishvananda/netlink@v1.3.0/nl/seg6_linux.go (about) 1 package nl 2 3 import ( 4 "errors" 5 "fmt" 6 "net" 7 ) 8 9 type IPv6SrHdr struct { 10 nextHdr uint8 11 hdrLen uint8 12 routingType uint8 13 segmentsLeft uint8 14 firstSegment uint8 15 flags uint8 16 reserved uint16 17 18 Segments []net.IP 19 } 20 21 func (s1 *IPv6SrHdr) Equal(s2 IPv6SrHdr) bool { 22 if len(s1.Segments) != len(s2.Segments) { 23 return false 24 } 25 for i := range s1.Segments { 26 if !s1.Segments[i].Equal(s2.Segments[i]) { 27 return false 28 } 29 } 30 return s1.nextHdr == s2.nextHdr && 31 s1.hdrLen == s2.hdrLen && 32 s1.routingType == s2.routingType && 33 s1.segmentsLeft == s2.segmentsLeft && 34 s1.firstSegment == s2.firstSegment && 35 s1.flags == s2.flags 36 // reserved doesn't need to be identical. 37 } 38 39 // seg6 encap mode 40 const ( 41 SEG6_IPTUN_MODE_INLINE = iota 42 SEG6_IPTUN_MODE_ENCAP 43 ) 44 45 // number of nested RTATTR 46 // from include/uapi/linux/seg6_iptunnel.h 47 const ( 48 SEG6_IPTUNNEL_UNSPEC = iota 49 SEG6_IPTUNNEL_SRH 50 __SEG6_IPTUNNEL_MAX 51 ) 52 const ( 53 SEG6_IPTUNNEL_MAX = __SEG6_IPTUNNEL_MAX - 1 54 ) 55 56 func EncodeSEG6Encap(mode int, segments []net.IP) ([]byte, error) { 57 nsegs := len(segments) // nsegs: number of segments 58 if nsegs == 0 { 59 return nil, errors.New("EncodeSEG6Encap: No Segment in srh") 60 } 61 b := make([]byte, 12, 12+len(segments)*16) 62 native := NativeEndian() 63 native.PutUint32(b, uint32(mode)) 64 b[4] = 0 // srh.nextHdr (0 when calling netlink) 65 b[5] = uint8(16 * nsegs >> 3) // srh.hdrLen (in 8-octets unit) 66 b[6] = IPV6_SRCRT_TYPE_4 // srh.routingType (assigned by IANA) 67 b[7] = uint8(nsegs - 1) // srh.segmentsLeft 68 b[8] = uint8(nsegs - 1) // srh.firstSegment 69 b[9] = 0 // srh.flags (SR6_FLAG1_HMAC for srh_hmac) 70 // srh.reserved: Defined as "Tag" in draft-ietf-6man-segment-routing-header-07 71 native.PutUint16(b[10:], 0) // srh.reserved 72 for _, netIP := range segments { 73 b = append(b, netIP...) // srh.Segments 74 } 75 return b, nil 76 } 77 78 func DecodeSEG6Encap(buf []byte) (int, []net.IP, error) { 79 native := NativeEndian() 80 mode := int(native.Uint32(buf)) 81 srh := IPv6SrHdr{ 82 nextHdr: buf[4], 83 hdrLen: buf[5], 84 routingType: buf[6], 85 segmentsLeft: buf[7], 86 firstSegment: buf[8], 87 flags: buf[9], 88 reserved: native.Uint16(buf[10:12]), 89 } 90 buf = buf[12:] 91 if len(buf)%16 != 0 { 92 err := fmt.Errorf("DecodeSEG6Encap: error parsing Segment List (buf len: %d)", len(buf)) 93 return mode, nil, err 94 } 95 for len(buf) > 0 { 96 srh.Segments = append(srh.Segments, net.IP(buf[:16])) 97 buf = buf[16:] 98 } 99 return mode, srh.Segments, nil 100 } 101 102 func DecodeSEG6Srh(buf []byte) ([]net.IP, error) { 103 native := NativeEndian() 104 srh := IPv6SrHdr{ 105 nextHdr: buf[0], 106 hdrLen: buf[1], 107 routingType: buf[2], 108 segmentsLeft: buf[3], 109 firstSegment: buf[4], 110 flags: buf[5], 111 reserved: native.Uint16(buf[6:8]), 112 } 113 buf = buf[8:] 114 if len(buf)%16 != 0 { 115 err := fmt.Errorf("DecodeSEG6Srh: error parsing Segment List (buf len: %d)", len(buf)) 116 return nil, err 117 } 118 for len(buf) > 0 { 119 srh.Segments = append(srh.Segments, net.IP(buf[:16])) 120 buf = buf[16:] 121 } 122 return srh.Segments, nil 123 } 124 func EncodeSEG6Srh(segments []net.IP) ([]byte, error) { 125 nsegs := len(segments) // nsegs: number of segments 126 if nsegs == 0 { 127 return nil, errors.New("EncodeSEG6Srh: No Segments") 128 } 129 b := make([]byte, 8, 8+len(segments)*16) 130 native := NativeEndian() 131 b[0] = 0 // srh.nextHdr (0 when calling netlink) 132 b[1] = uint8(16 * nsegs >> 3) // srh.hdrLen (in 8-octets unit) 133 b[2] = IPV6_SRCRT_TYPE_4 // srh.routingType (assigned by IANA) 134 b[3] = uint8(nsegs - 1) // srh.segmentsLeft 135 b[4] = uint8(nsegs - 1) // srh.firstSegment 136 b[5] = 0 // srh.flags (SR6_FLAG1_HMAC for srh_hmac) 137 // srh.reserved: Defined as "Tag" in draft-ietf-6man-segment-routing-header-07 138 native.PutUint16(b[6:], 0) // srh.reserved 139 for _, netIP := range segments { 140 b = append(b, netIP...) // srh.Segments 141 } 142 return b, nil 143 } 144 145 // Helper functions 146 func SEG6EncapModeString(mode int) string { 147 switch mode { 148 case SEG6_IPTUN_MODE_INLINE: 149 return "inline" 150 case SEG6_IPTUN_MODE_ENCAP: 151 return "encap" 152 } 153 return "unknown" 154 }