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 }