github.com/elfadel/cilium@v1.6.12/pkg/datapath/linux/route/route.go (about)

     1  // Copyright 2016-2018 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package route
    16  
    17  import (
    18  	"fmt"
    19  	"net"
    20  
    21  	"github.com/cilium/cilium/pkg/logging/logfields"
    22  	"github.com/cilium/cilium/pkg/option"
    23  
    24  	"github.com/sirupsen/logrus"
    25  	"github.com/vishvananda/netlink"
    26  )
    27  
    28  type Route struct {
    29  	Prefix  net.IPNet
    30  	Nexthop *net.IP
    31  	Local   net.IP
    32  	Device  string
    33  	MTU     int
    34  	Proto   int
    35  	Scope   netlink.Scope
    36  	Table   int
    37  	Type    int
    38  }
    39  
    40  // LogFields returns the route attributes as logrus.Fields map
    41  func (r *Route) LogFields() logrus.Fields {
    42  	return logrus.Fields{
    43  		"prefix":            r.Prefix,
    44  		"nexthop":           r.Nexthop,
    45  		"local":             r.Local,
    46  		logfields.Interface: r.Device,
    47  	}
    48  }
    49  
    50  func (r *Route) getLogger() *logrus.Entry {
    51  	return log.WithFields(r.LogFields())
    52  }
    53  
    54  // ByMask is used to sort an array of routes by mask, narrow first.
    55  type ByMask []Route
    56  
    57  func (a ByMask) Len() int {
    58  	return len(a)
    59  }
    60  
    61  func (a ByMask) Less(i, j int) bool {
    62  	lenA, _ := a[i].Prefix.Mask.Size()
    63  	lenB, _ := a[j].Prefix.Mask.Size()
    64  	return lenA > lenB
    65  }
    66  
    67  func (a ByMask) Swap(i, j int) {
    68  	a[i], a[j] = a[j], a[i]
    69  }
    70  
    71  // ToIPCommand converts the route into a full "ip route ..." command
    72  func (r *Route) ToIPCommand(dev string) []string {
    73  	res := []string{"ip"}
    74  	if r.Prefix.IP.To4() == nil {
    75  		res = append(res, "-6")
    76  	}
    77  	res = append(res, "route", "add", r.Prefix.String())
    78  	if r.Nexthop != nil {
    79  		res = append(res, "via", r.Nexthop.String())
    80  	}
    81  	if r.MTU != 0 {
    82  		res = append(res, "mtu", fmt.Sprintf("%d", r.MTU))
    83  	}
    84  	res = append(res, "dev", dev)
    85  	return res
    86  }
    87  
    88  func lookupDefaultRoute(family int) (netlink.Route, error) {
    89  	routes, err := netlink.RouteListFiltered(family, &netlink.Route{Dst: nil}, netlink.RT_FILTER_DST)
    90  	if err != nil {
    91  		return netlink.Route{}, fmt.Errorf("Unable to list direct routes: %s", err)
    92  	}
    93  
    94  	if len(routes) != 1 {
    95  		return netlink.Route{}, fmt.Errorf("Found (%d) default routes", len(routes))
    96  	}
    97  
    98  	log.Debugf("Found default route on node %v", routes[0])
    99  	return routes[0], nil
   100  }
   101  
   102  // NodeDeviceWithDefaultRoute returns the node's device which handles the
   103  // default route in the current namespace
   104  func NodeDeviceWithDefaultRoute() (netlink.Link, error) {
   105  	linkIndex := 0
   106  	if option.Config.EnableIPv4 {
   107  		route, err := lookupDefaultRoute(netlink.FAMILY_V4)
   108  		if err != nil {
   109  			return nil, err
   110  		}
   111  		linkIndex = route.LinkIndex
   112  	}
   113  	if option.Config.EnableIPv6 {
   114  		route, err := lookupDefaultRoute(netlink.FAMILY_V6)
   115  		if err != nil {
   116  			return nil, err
   117  		}
   118  		if linkIndex != 0 && linkIndex != route.LinkIndex {
   119  			return nil, fmt.Errorf("IPv4/IPv6 have different link indices")
   120  		}
   121  		linkIndex = route.LinkIndex
   122  	}
   123  	link, err := netlink.LinkByIndex(linkIndex)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  	return link, nil
   128  }