seg6_linux.go 4.0 KB

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