2014-09-01 03:27:34 +00:00
|
|
|
package netlink
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
2017-02-19 03:22:09 +00:00
|
|
|
"strings"
|
2014-09-15 00:44:56 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Scope is an enum representing a route scope.
|
|
|
|
type Scope uint8
|
|
|
|
|
2015-10-09 08:09:44 +00:00
|
|
|
type NextHopFlag int
|
|
|
|
|
2022-02-09 07:03:57 +00:00
|
|
|
const (
|
|
|
|
RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota)
|
|
|
|
RT_FILTER_SCOPE
|
|
|
|
RT_FILTER_TYPE
|
|
|
|
RT_FILTER_TOS
|
|
|
|
RT_FILTER_IIF
|
|
|
|
RT_FILTER_OIF
|
|
|
|
RT_FILTER_DST
|
|
|
|
RT_FILTER_SRC
|
|
|
|
RT_FILTER_GW
|
|
|
|
RT_FILTER_TABLE
|
|
|
|
RT_FILTER_HOPLIMIT
|
|
|
|
RT_FILTER_PRIORITY
|
|
|
|
RT_FILTER_MARK
|
|
|
|
RT_FILTER_MASK
|
|
|
|
RT_FILTER_REALM
|
|
|
|
)
|
|
|
|
|
2017-02-19 03:22:09 +00:00
|
|
|
type Destination interface {
|
|
|
|
Family() int
|
|
|
|
Decode([]byte) error
|
|
|
|
Encode() ([]byte, error)
|
|
|
|
String() string
|
2017-09-15 12:32:21 +00:00
|
|
|
Equal(Destination) bool
|
2017-02-19 03:22:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Encap interface {
|
|
|
|
Type() int
|
|
|
|
Decode([]byte) error
|
|
|
|
Encode() ([]byte, error)
|
|
|
|
String() string
|
2017-09-15 12:32:21 +00:00
|
|
|
Equal(Encap) bool
|
2017-02-19 03:22:09 +00:00
|
|
|
}
|
|
|
|
|
2021-03-04 08:13:14 +00:00
|
|
|
//Protocol describe what was the originator of the route
|
|
|
|
type RouteProtocol int
|
|
|
|
|
2015-11-26 15:09:33 +00:00
|
|
|
// Route represents a netlink route.
|
2014-09-01 03:27:34 +00:00
|
|
|
type Route struct {
|
2020-09-29 13:23:42 +00:00
|
|
|
LinkIndex int
|
|
|
|
ILinkIndex int
|
|
|
|
Scope Scope
|
|
|
|
Dst *net.IPNet
|
|
|
|
Src net.IP
|
|
|
|
Gw net.IP
|
|
|
|
MultiPath []*NexthopInfo
|
2021-03-04 08:13:14 +00:00
|
|
|
Protocol RouteProtocol
|
2020-09-29 13:23:42 +00:00
|
|
|
Priority int
|
2021-05-19 14:26:52 +00:00
|
|
|
Family int
|
2020-09-29 13:23:42 +00:00
|
|
|
Table int
|
|
|
|
Type int
|
|
|
|
Tos int
|
|
|
|
Flags int
|
|
|
|
MPLSDst *int
|
|
|
|
NewDst Destination
|
|
|
|
Encap Encap
|
2020-10-29 02:03:23 +00:00
|
|
|
Via Destination
|
2021-08-25 14:03:09 +00:00
|
|
|
Realm int
|
2020-09-29 13:23:42 +00:00
|
|
|
MTU int
|
|
|
|
Window int
|
|
|
|
Rtt int
|
|
|
|
RttVar int
|
|
|
|
Ssthresh int
|
|
|
|
Cwnd int
|
|
|
|
AdvMSS int
|
|
|
|
Reordering int
|
|
|
|
Hoplimit int
|
|
|
|
InitCwnd int
|
|
|
|
Features int
|
|
|
|
RtoMin int
|
|
|
|
InitRwnd int
|
|
|
|
QuickACK int
|
|
|
|
Congctl string
|
|
|
|
FastOpenNoCookie int
|
2014-09-01 03:27:34 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (r Route) String() string {
|
2017-02-19 03:22:09 +00:00
|
|
|
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))
|
|
|
|
}
|
2020-10-29 02:03:23 +00:00
|
|
|
if r.Via != nil {
|
|
|
|
elems = append(elems, fmt.Sprintf("Via: %s", r.Via))
|
|
|
|
}
|
2017-02-19 03:22:09 +00:00
|
|
|
elems = append(elems, fmt.Sprintf("Src: %s", r.Src))
|
2016-06-15 05:02:24 +00:00
|
|
|
if len(r.MultiPath) > 0 {
|
2017-02-19 03:22:09 +00:00
|
|
|
elems = append(elems, fmt.Sprintf("Gw: %s", r.MultiPath))
|
|
|
|
} else {
|
|
|
|
elems = append(elems, fmt.Sprintf("Gw: %s", r.Gw))
|
2016-06-15 05:02:24 +00:00
|
|
|
}
|
2017-02-19 03:22:09 +00:00
|
|
|
elems = append(elems, fmt.Sprintf("Flags: %s", r.ListFlags()))
|
|
|
|
elems = append(elems, fmt.Sprintf("Table: %d", r.Table))
|
2021-08-25 14:03:09 +00:00
|
|
|
elems = append(elems, fmt.Sprintf("Realm: %d", r.Realm))
|
2017-02-19 03:22:09 +00:00
|
|
|
return fmt.Sprintf("{%s}", strings.Join(elems, " "))
|
2015-10-09 08:09:44 +00:00
|
|
|
}
|
|
|
|
|
2017-09-15 12:32:21 +00:00
|
|
|
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 &&
|
2021-08-25 14:03:09 +00:00
|
|
|
r.Realm == x.Realm &&
|
2017-09-15 12:32:21 +00:00
|
|
|
r.Table == x.Table &&
|
|
|
|
r.Type == x.Type &&
|
|
|
|
r.Tos == x.Tos &&
|
2018-09-05 17:59:55 +00:00
|
|
|
r.Hoplimit == x.Hoplimit &&
|
2017-09-15 12:32:21 +00:00
|
|
|
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))) &&
|
2020-10-29 02:03:23 +00:00
|
|
|
(r.Via == x.Via || (r.Via != nil && r.Via.Equal(x.Via))) &&
|
2017-09-15 12:32:21 +00:00
|
|
|
(r.Encap == x.Encap || (r.Encap != nil && r.Encap.Equal(x.Encap)))
|
|
|
|
}
|
|
|
|
|
2015-10-09 08:09:44 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2015-08-19 14:42:33 +00:00
|
|
|
// RouteUpdate is sent when a route changes - type is RTM_NEWROUTE or RTM_DELROUTE
|
2023-11-30 12:36:33 +00:00
|
|
|
|
|
|
|
// NlFlags is only non-zero for RTM_NEWROUTE, the following flags can be set:
|
|
|
|
// - unix.NLM_F_REPLACE - Replace existing matching config object with this request
|
|
|
|
// - unix.NLM_F_EXCL - Don't replace the config object if it already exists
|
|
|
|
// - unix.NLM_F_CREATE - Create config object if it doesn't already exist
|
|
|
|
// - unix.NLM_F_APPEND - Add to the end of the object list
|
2015-08-19 14:42:33 +00:00
|
|
|
type RouteUpdate struct {
|
2023-11-30 12:36:33 +00:00
|
|
|
Type uint16
|
|
|
|
NlFlags uint16
|
2015-08-19 14:42:33 +00:00
|
|
|
Route
|
|
|
|
}
|
2016-06-15 05:02:24 +00:00
|
|
|
|
|
|
|
type NexthopInfo struct {
|
|
|
|
LinkIndex int
|
|
|
|
Hops int
|
|
|
|
Gw net.IP
|
2016-08-22 02:40:27 +00:00
|
|
|
Flags int
|
2017-02-19 03:22:09 +00:00
|
|
|
NewDst Destination
|
|
|
|
Encap Encap
|
2020-10-29 02:03:23 +00:00
|
|
|
Via Destination
|
2016-06-15 05:02:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (n *NexthopInfo) String() string {
|
2017-02-19 03:22:09 +00:00
|
|
|
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))
|
|
|
|
}
|
2020-10-29 02:03:23 +00:00
|
|
|
if n.Via != nil {
|
|
|
|
elems = append(elems, fmt.Sprintf("Via: %s", n.Via))
|
|
|
|
}
|
2017-02-19 03:22:09 +00:00
|
|
|
elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1))
|
2017-09-11 14:05:27 +00:00
|
|
|
elems = append(elems, fmt.Sprintf("Gw: %s", n.Gw))
|
2017-02-19 03:22:09 +00:00
|
|
|
elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags()))
|
|
|
|
return fmt.Sprintf("{%s}", strings.Join(elems, " "))
|
2016-06-15 05:02:24 +00:00
|
|
|
}
|
2017-09-15 09:37:11 +00:00
|
|
|
|
2017-09-15 12:32:21 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2017-09-15 09:37:11 +00:00
|
|
|
// 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)
|
|
|
|
}
|