seg6_linux.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  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]) != true {
  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)\n", 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. // Helper functions
  94. func SEG6EncapModeString(mode int) string {
  95. switch mode {
  96. case SEG6_IPTUN_MODE_INLINE:
  97. return "inline"
  98. case SEG6_IPTUN_MODE_ENCAP:
  99. return "encap"
  100. }
  101. return "unknown"
  102. }