package netlink import ( "fmt" "net" "strings" ) // Scope is an enum representing a route scope. type Scope uint8 type NextHopFlag int type Destination interface { Family() int Decode([]byte) error Encode() ([]byte, error) String() string Equal(Destination) bool } type Encap interface { Type() int Decode([]byte) error Encode() ([]byte, error) String() string Equal(Encap) bool } // Route represents a netlink route. type Route struct { LinkIndex int ILinkIndex int Scope Scope Dst *net.IPNet Src net.IP Gw net.IP MultiPath []*NexthopInfo Protocol int Priority int Table int Type int Tos int Flags int MPLSDst *int NewDst Destination Encap Encap MTU int AdvMSS int } func (r Route) String() string { elems := []string{} if len(r.MultiPath) == 0 { elems = append(elems, fmt.Sprintf("Ifindex: %d", r.LinkIndex)) } if r.MPLSDst != nil { elems = append(elems, fmt.Sprintf("Dst: %d", r.MPLSDst)) } else { elems = append(elems, fmt.Sprintf("Dst: %s", r.Dst)) } if r.NewDst != nil { elems = append(elems, fmt.Sprintf("NewDst: %s", r.NewDst)) } if r.Encap != nil { elems = append(elems, fmt.Sprintf("Encap: %s", r.Encap)) } elems = append(elems, fmt.Sprintf("Src: %s", r.Src)) if len(r.MultiPath) > 0 { elems = append(elems, fmt.Sprintf("Gw: %s", r.MultiPath)) } else { elems = append(elems, fmt.Sprintf("Gw: %s", r.Gw)) } elems = append(elems, fmt.Sprintf("Flags: %s", r.ListFlags())) elems = append(elems, fmt.Sprintf("Table: %d", r.Table)) return fmt.Sprintf("{%s}", strings.Join(elems, " ")) } func (r Route) Equal(x Route) bool { return r.LinkIndex == x.LinkIndex && r.ILinkIndex == x.ILinkIndex && r.Scope == x.Scope && ipNetEqual(r.Dst, x.Dst) && r.Src.Equal(x.Src) && r.Gw.Equal(x.Gw) && nexthopInfoSlice(r.MultiPath).Equal(x.MultiPath) && r.Protocol == x.Protocol && r.Priority == x.Priority && r.Table == x.Table && r.Type == x.Type && r.Tos == x.Tos && r.Flags == x.Flags && (r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) && (r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) && (r.Encap == x.Encap || (r.Encap != nil && r.Encap.Equal(x.Encap))) } func (r *Route) SetFlag(flag NextHopFlag) { r.Flags |= int(flag) } func (r *Route) ClearFlag(flag NextHopFlag) { r.Flags &^= int(flag) } type flagString struct { f NextHopFlag s string } // RouteUpdate is sent when a route changes - type is RTM_NEWROUTE or RTM_DELROUTE type RouteUpdate struct { Type uint16 Route } type NexthopInfo struct { LinkIndex int Hops int Gw net.IP Flags int NewDst Destination Encap Encap } func (n *NexthopInfo) String() string { elems := []string{} elems = append(elems, fmt.Sprintf("Ifindex: %d", n.LinkIndex)) if n.NewDst != nil { elems = append(elems, fmt.Sprintf("NewDst: %s", n.NewDst)) } if n.Encap != nil { elems = append(elems, fmt.Sprintf("Encap: %s", n.Encap)) } elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1)) elems = append(elems, fmt.Sprintf("Gw: %s", n.Gw)) elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags())) return fmt.Sprintf("{%s}", strings.Join(elems, " ")) } func (n NexthopInfo) Equal(x NexthopInfo) bool { return n.LinkIndex == x.LinkIndex && n.Hops == x.Hops && n.Gw.Equal(x.Gw) && n.Flags == x.Flags && (n.NewDst == x.NewDst || (n.NewDst != nil && n.NewDst.Equal(x.NewDst))) && (n.Encap == x.Encap || (n.Encap != nil && n.Encap.Equal(x.Encap))) } type nexthopInfoSlice []*NexthopInfo func (n nexthopInfoSlice) Equal(x []*NexthopInfo) bool { if len(n) != len(x) { return false } for i := range n { if n[i] == nil || x[i] == nil { return false } if !n[i].Equal(*x[i]) { return false } } return true } // ipNetEqual returns true iff both IPNet are equal func ipNetEqual(ipn1 *net.IPNet, ipn2 *net.IPNet) bool { if ipn1 == ipn2 { return true } if ipn1 == nil || ipn2 == nil { return false } m1, _ := ipn1.Mask.Size() m2, _ := ipn2.Mask.Size() return m1 == m2 && ipn1.IP.Equal(ipn2.IP) }