github.com/sagernet/netlink@v0.0.0-20240612041022-b9a21c07ac6a/route.go (about)

     1  package netlink
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strings"
     7  )
     8  
     9  // Scope is an enum representing a route scope.
    10  type Scope uint8
    11  
    12  type NextHopFlag int
    13  
    14  const (
    15  	RT_FILTER_PROTOCOL uint64 = 1 << (1 + iota)
    16  	RT_FILTER_SCOPE
    17  	RT_FILTER_TYPE
    18  	RT_FILTER_TOS
    19  	RT_FILTER_IIF
    20  	RT_FILTER_OIF
    21  	RT_FILTER_DST
    22  	RT_FILTER_SRC
    23  	RT_FILTER_GW
    24  	RT_FILTER_TABLE
    25  	RT_FILTER_HOPLIMIT
    26  	RT_FILTER_PRIORITY
    27  	RT_FILTER_MARK
    28  	RT_FILTER_MASK
    29  	RT_FILTER_REALM
    30  )
    31  
    32  type Destination interface {
    33  	Family() int
    34  	Decode([]byte) error
    35  	Encode() ([]byte, error)
    36  	String() string
    37  	Equal(Destination) bool
    38  }
    39  
    40  type Encap interface {
    41  	Type() int
    42  	Decode([]byte) error
    43  	Encode() ([]byte, error)
    44  	String() string
    45  	Equal(Encap) bool
    46  }
    47  
    48  // Protocol describe what was the originator of the route
    49  type RouteProtocol int
    50  
    51  // Route represents a netlink route.
    52  type Route struct {
    53  	LinkIndex        int
    54  	ILinkIndex       int
    55  	Scope            Scope
    56  	Dst              *net.IPNet
    57  	Src              net.IP
    58  	Gw               net.IP
    59  	MultiPath        []*NexthopInfo
    60  	Protocol         RouteProtocol
    61  	Priority         int
    62  	Family           int
    63  	Table            int
    64  	Type             int
    65  	Tos              int
    66  	Flags            int
    67  	MPLSDst          *int
    68  	NewDst           Destination
    69  	Encap            Encap
    70  	Via              Destination
    71  	Realm            int
    72  	MTU              int
    73  	Window           int
    74  	Rtt              int
    75  	RttVar           int
    76  	Ssthresh         int
    77  	Cwnd             int
    78  	AdvMSS           int
    79  	Reordering       int
    80  	Hoplimit         int
    81  	InitCwnd         int
    82  	Features         int
    83  	RtoMin           int
    84  	InitRwnd         int
    85  	QuickACK         int
    86  	Congctl          string
    87  	FastOpenNoCookie int
    88  }
    89  
    90  func (r Route) String() string {
    91  	elems := []string{}
    92  	if len(r.MultiPath) == 0 {
    93  		elems = append(elems, fmt.Sprintf("Ifindex: %d", r.LinkIndex))
    94  	}
    95  	if r.MPLSDst != nil {
    96  		elems = append(elems, fmt.Sprintf("Dst: %d", r.MPLSDst))
    97  	} else {
    98  		elems = append(elems, fmt.Sprintf("Dst: %s", r.Dst))
    99  	}
   100  	if r.NewDst != nil {
   101  		elems = append(elems, fmt.Sprintf("NewDst: %s", r.NewDst))
   102  	}
   103  	if r.Encap != nil {
   104  		elems = append(elems, fmt.Sprintf("Encap: %s", r.Encap))
   105  	}
   106  	if r.Via != nil {
   107  		elems = append(elems, fmt.Sprintf("Via: %s", r.Via))
   108  	}
   109  	elems = append(elems, fmt.Sprintf("Src: %s", r.Src))
   110  	if len(r.MultiPath) > 0 {
   111  		elems = append(elems, fmt.Sprintf("Gw: %s", r.MultiPath))
   112  	} else {
   113  		elems = append(elems, fmt.Sprintf("Gw: %s", r.Gw))
   114  	}
   115  	elems = append(elems, fmt.Sprintf("Flags: %s", r.ListFlags()))
   116  	elems = append(elems, fmt.Sprintf("Table: %d", r.Table))
   117  	elems = append(elems, fmt.Sprintf("Realm: %d", r.Realm))
   118  	return fmt.Sprintf("{%s}", strings.Join(elems, " "))
   119  }
   120  
   121  func (r Route) Equal(x Route) bool {
   122  	return r.LinkIndex == x.LinkIndex &&
   123  		r.ILinkIndex == x.ILinkIndex &&
   124  		r.Scope == x.Scope &&
   125  		ipNetEqual(r.Dst, x.Dst) &&
   126  		r.Src.Equal(x.Src) &&
   127  		r.Gw.Equal(x.Gw) &&
   128  		nexthopInfoSlice(r.MultiPath).Equal(x.MultiPath) &&
   129  		r.Protocol == x.Protocol &&
   130  		r.Priority == x.Priority &&
   131  		r.Realm == x.Realm &&
   132  		r.Table == x.Table &&
   133  		r.Type == x.Type &&
   134  		r.Tos == x.Tos &&
   135  		r.Hoplimit == x.Hoplimit &&
   136  		r.Flags == x.Flags &&
   137  		(r.MPLSDst == x.MPLSDst || (r.MPLSDst != nil && x.MPLSDst != nil && *r.MPLSDst == *x.MPLSDst)) &&
   138  		(r.NewDst == x.NewDst || (r.NewDst != nil && r.NewDst.Equal(x.NewDst))) &&
   139  		(r.Via == x.Via || (r.Via != nil && r.Via.Equal(x.Via))) &&
   140  		(r.Encap == x.Encap || (r.Encap != nil && r.Encap.Equal(x.Encap)))
   141  }
   142  
   143  func (r *Route) SetFlag(flag NextHopFlag) {
   144  	r.Flags |= int(flag)
   145  }
   146  
   147  func (r *Route) ClearFlag(flag NextHopFlag) {
   148  	r.Flags &^= int(flag)
   149  }
   150  
   151  type flagString struct {
   152  	f NextHopFlag
   153  	s string
   154  }
   155  
   156  // RouteUpdate is sent when a route changes - type is RTM_NEWROUTE or RTM_DELROUTE
   157  type RouteUpdate struct {
   158  	Type uint16
   159  	Route
   160  }
   161  
   162  type NexthopInfo struct {
   163  	LinkIndex int
   164  	Hops      int
   165  	Gw        net.IP
   166  	Flags     int
   167  	NewDst    Destination
   168  	Encap     Encap
   169  	Via       Destination
   170  }
   171  
   172  func (n *NexthopInfo) String() string {
   173  	elems := []string{}
   174  	elems = append(elems, fmt.Sprintf("Ifindex: %d", n.LinkIndex))
   175  	if n.NewDst != nil {
   176  		elems = append(elems, fmt.Sprintf("NewDst: %s", n.NewDst))
   177  	}
   178  	if n.Encap != nil {
   179  		elems = append(elems, fmt.Sprintf("Encap: %s", n.Encap))
   180  	}
   181  	if n.Via != nil {
   182  		elems = append(elems, fmt.Sprintf("Via: %s", n.Via))
   183  	}
   184  	elems = append(elems, fmt.Sprintf("Weight: %d", n.Hops+1))
   185  	elems = append(elems, fmt.Sprintf("Gw: %s", n.Gw))
   186  	elems = append(elems, fmt.Sprintf("Flags: %s", n.ListFlags()))
   187  	return fmt.Sprintf("{%s}", strings.Join(elems, " "))
   188  }
   189  
   190  func (n NexthopInfo) Equal(x NexthopInfo) bool {
   191  	return n.LinkIndex == x.LinkIndex &&
   192  		n.Hops == x.Hops &&
   193  		n.Gw.Equal(x.Gw) &&
   194  		n.Flags == x.Flags &&
   195  		(n.NewDst == x.NewDst || (n.NewDst != nil && n.NewDst.Equal(x.NewDst))) &&
   196  		(n.Encap == x.Encap || (n.Encap != nil && n.Encap.Equal(x.Encap)))
   197  }
   198  
   199  type nexthopInfoSlice []*NexthopInfo
   200  
   201  func (n nexthopInfoSlice) Equal(x []*NexthopInfo) bool {
   202  	if len(n) != len(x) {
   203  		return false
   204  	}
   205  	for i := range n {
   206  		if n[i] == nil || x[i] == nil {
   207  			return false
   208  		}
   209  		if !n[i].Equal(*x[i]) {
   210  			return false
   211  		}
   212  	}
   213  	return true
   214  }
   215  
   216  // ipNetEqual returns true iff both IPNet are equal
   217  func ipNetEqual(ipn1 *net.IPNet, ipn2 *net.IPNet) bool {
   218  	if ipn1 == ipn2 {
   219  		return true
   220  	}
   221  	if ipn1 == nil || ipn2 == nil {
   222  		return false
   223  	}
   224  	m1, _ := ipn1.Mask.Size()
   225  	m2, _ := ipn2.Mask.Size()
   226  	return m1 == m2 && ipn1.IP.Equal(ipn2.IP)
   227  }