1package netlink 2 3import ( 4 "fmt" 5 "net" 6 "strings" 7) 8 9// Scope is an enum representing a route scope. 10type Scope uint8 11 12type NextHopFlag int 13 14type Destination interface { 15 Family() int 16 Decode([]byte) error 17 Encode() ([]byte, error) 18 String() string 19 Equal(Destination) bool 20} 21 22type Encap interface { 23 Type() int 24 Decode([]byte) error 25 Encode() ([]byte, error) 26 String() string 27 Equal(Encap) bool 28} 29 30// Route represents a netlink route. 31type Route struct { 32 LinkIndex int 33 ILinkIndex int 34 Scope Scope 35 Dst *net.IPNet 36 Src net.IP 37 Gw net.IP 38 MultiPath []*NexthopInfo 39 Protocol int 40 Priority int 41 Table int 42 Type int 43 Tos int 44 Flags int 45 MPLSDst *int 46 NewDst Destination 47 Encap Encap 48 MTU int 49 AdvMSS int 50 Hoplimit int 51} 52 53func (r Route) String() string { 54 elems := []string{} 55 if len(r.MultiPath) == 0 { 56 elems = append(elems, fmt.Sprintf("Ifindex: %d", r.LinkIndex)) 57 } 58 if r.MPLSDst != nil { 59 elems = append(elems, fmt.Sprintf("Dst: %d", r.MPLSDst)) 60 } else { 61 elems = append(elems, fmt.Sprintf("Dst: %s", r.Dst)) 62 } 63 if r.NewDst != nil { 64 elems = append(elems, fmt.Sprintf("NewDst: %s", r.NewDst)) 65 } 66 if r.Encap != nil { 67 elems = append(elems, fmt.Sprintf("Encap: %s", r.Encap)) 68 } 69 elems = append(elems, fmt.Sprintf("Src: %s", r.Src)) 70 if len(r.MultiPath) > 0 { 71 elems = append(elems, fmt.Sprintf("Gw: %s", r.MultiPath)) 72 } else { 73 elems = append(elems, fmt.Sprintf("Gw: %s", r.Gw)) 74 } 75 elems = append(elems, fmt.Sprintf("Flags: %s", r.ListFlags())) 76 elems = append(elems, fmt.Sprintf("Table: %d", r.Table)) 77 return fmt.Sprintf("{%s}", strings.Join(elems, " ")) 78} 79 80func (r Route) Equal(x Route) bool { 81 return r.LinkIndex == x.LinkIndex && 82 r.ILinkIndex == x.ILinkIndex && 83 r.Scope == x.Scope && 84 ipNetEqual(r.Dst, x.Dst) && 85 r.Src.Equal(x.Src) && 86 r.Gw.Equal(x.Gw) && 87 nexthopInfoSlice(r.MultiPath).Equal(x.MultiPath) && 88 r.Protocol == x.Protocol && 89 r.Priority == x.Priority && 90 r.Table == x.Table && 91 r.Type == x.Type && 92 r.Tos == x.Tos && 93 r.Hoplimit == x.Hoplimit && 94 r.Flags == x.Flags && 95 (r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) && 96 (r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) && 97 (r.Encap == x.Encap || (r.Encap != nil && r.Encap.Equal(x.Encap))) 98} 99 100func (r *Route) SetFlag(flag NextHopFlag) { 101 r.Flags |= int(flag) 102} 103 104func (r *Route) ClearFlag(flag NextHopFlag) { 105 r.Flags &^= int(flag) 106} 107 108type flagString struct { 109 f NextHopFlag 110 s string 111} 112 113// RouteUpdate is sent when a route changes - type is RTM_NEWROUTE or RTM_DELROUTE 114type RouteUpdate struct { 115 Type uint16 116 Route 117} 118 119type NexthopInfo struct { 120 LinkIndex int 121 Hops int 122 Gw net.IP 123 Flags int 124 NewDst Destination 125 Encap Encap 126} 127 128func (n *NexthopInfo) String() string { 129 elems := []string{} 130 elems = append(elems, fmt.Sprintf("Ifindex: %d", n.LinkIndex)) 131 if n.NewDst != nil { 132 elems = append(elems, fmt.Sprintf("NewDst: %s", n.NewDst)) 133 } 134 if n.Encap != nil { 135 elems = append(elems, fmt.Sprintf("Encap: %s", n.Encap)) 136 } 137 elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1)) 138 elems = append(elems, fmt.Sprintf("Gw: %s", n.Gw)) 139 elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags())) 140 return fmt.Sprintf("{%s}", strings.Join(elems, " ")) 141} 142 143func (n NexthopInfo) Equal(x NexthopInfo) bool { 144 return n.LinkIndex == x.LinkIndex && 145 n.Hops == x.Hops && 146 n.Gw.Equal(x.Gw) && 147 n.Flags == x.Flags && 148 (n.NewDst == x.NewDst || (n.NewDst != nil && n.NewDst.Equal(x.NewDst))) && 149 (n.Encap == x.Encap || (n.Encap != nil && n.Encap.Equal(x.Encap))) 150} 151 152type nexthopInfoSlice []*NexthopInfo 153 154func (n nexthopInfoSlice) Equal(x []*NexthopInfo) bool { 155 if len(n) != len(x) { 156 return false 157 } 158 for i := range n { 159 if n[i] == nil || x[i] == nil { 160 return false 161 } 162 if !n[i].Equal(*x[i]) { 163 return false 164 } 165 } 166 return true 167} 168 169// ipNetEqual returns true iff both IPNet are equal 170func ipNetEqual(ipn1 *net.IPNet, ipn2 *net.IPNet) bool { 171 if ipn1 == ipn2 { 172 return true 173 } 174 if ipn1 == nil || ipn2 == nil { 175 return false 176 } 177 m1, _ := ipn1.Mask.Size() 178 m2, _ := ipn2.Mask.Size() 179 return m1 == m2 && ipn1.IP.Equal(ipn2.IP) 180} 181