github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/libnetwork/osl/route_linux.go (about) 1 package osl 2 3 import ( 4 "fmt" 5 "net" 6 7 "github.com/docker/docker/libnetwork/types" 8 "github.com/vishvananda/netlink" 9 ) 10 11 func (n *networkNamespace) Gateway() net.IP { 12 n.Lock() 13 defer n.Unlock() 14 15 return n.gw 16 } 17 18 func (n *networkNamespace) GatewayIPv6() net.IP { 19 n.Lock() 20 defer n.Unlock() 21 22 return n.gwv6 23 } 24 25 func (n *networkNamespace) StaticRoutes() []*types.StaticRoute { 26 n.Lock() 27 defer n.Unlock() 28 29 routes := make([]*types.StaticRoute, len(n.staticRoutes)) 30 for i, route := range n.staticRoutes { 31 r := route.GetCopy() 32 routes[i] = r 33 } 34 35 return routes 36 } 37 38 func (n *networkNamespace) setGateway(gw net.IP) { 39 n.Lock() 40 n.gw = gw 41 n.Unlock() 42 } 43 44 func (n *networkNamespace) setGatewayIPv6(gwv6 net.IP) { 45 n.Lock() 46 n.gwv6 = gwv6 47 n.Unlock() 48 } 49 50 func (n *networkNamespace) SetGateway(gw net.IP) error { 51 // Silently return if the gateway is empty 52 if len(gw) == 0 { 53 return nil 54 } 55 56 err := n.programGateway(gw, true) 57 if err == nil { 58 n.setGateway(gw) 59 } 60 61 return err 62 } 63 64 func (n *networkNamespace) UnsetGateway() error { 65 gw := n.Gateway() 66 67 // Silently return if the gateway is empty 68 if len(gw) == 0 { 69 return nil 70 } 71 72 err := n.programGateway(gw, false) 73 if err == nil { 74 n.setGateway(net.IP{}) 75 } 76 77 return err 78 } 79 80 func (n *networkNamespace) programGateway(gw net.IP, isAdd bool) error { 81 gwRoutes, err := n.nlHandle.RouteGet(gw) 82 if err != nil { 83 return fmt.Errorf("route for the gateway %s could not be found: %v", gw, err) 84 } 85 86 var linkIndex int 87 for _, gwRoute := range gwRoutes { 88 if gwRoute.Gw == nil { 89 linkIndex = gwRoute.LinkIndex 90 break 91 } 92 } 93 94 if linkIndex == 0 { 95 return fmt.Errorf("Direct route for the gateway %s could not be found", gw) 96 } 97 98 if isAdd { 99 return n.nlHandle.RouteAdd(&netlink.Route{ 100 Scope: netlink.SCOPE_UNIVERSE, 101 LinkIndex: linkIndex, 102 Gw: gw, 103 }) 104 } 105 106 return n.nlHandle.RouteDel(&netlink.Route{ 107 Scope: netlink.SCOPE_UNIVERSE, 108 LinkIndex: linkIndex, 109 Gw: gw, 110 }) 111 } 112 113 // Program a route in to the namespace routing table. 114 func (n *networkNamespace) programRoute(path string, dest *net.IPNet, nh net.IP) error { 115 gwRoutes, err := n.nlHandle.RouteGet(nh) 116 if err != nil { 117 return fmt.Errorf("route for the next hop %s could not be found: %v", nh, err) 118 } 119 120 return n.nlHandle.RouteAdd(&netlink.Route{ 121 Scope: netlink.SCOPE_UNIVERSE, 122 LinkIndex: gwRoutes[0].LinkIndex, 123 Gw: nh, 124 Dst: dest, 125 }) 126 } 127 128 // Delete a route from the namespace routing table. 129 func (n *networkNamespace) removeRoute(path string, dest *net.IPNet, nh net.IP) error { 130 gwRoutes, err := n.nlHandle.RouteGet(nh) 131 if err != nil { 132 return fmt.Errorf("route for the next hop could not be found: %v", err) 133 } 134 135 return n.nlHandle.RouteDel(&netlink.Route{ 136 Scope: netlink.SCOPE_UNIVERSE, 137 LinkIndex: gwRoutes[0].LinkIndex, 138 Gw: nh, 139 Dst: dest, 140 }) 141 } 142 143 func (n *networkNamespace) SetGatewayIPv6(gwv6 net.IP) error { 144 // Silently return if the gateway is empty 145 if len(gwv6) == 0 { 146 return nil 147 } 148 149 err := n.programGateway(gwv6, true) 150 if err == nil { 151 n.setGatewayIPv6(gwv6) 152 } 153 154 return err 155 } 156 157 func (n *networkNamespace) UnsetGatewayIPv6() error { 158 gwv6 := n.GatewayIPv6() 159 160 // Silently return if the gateway is empty 161 if len(gwv6) == 0 { 162 return nil 163 } 164 165 err := n.programGateway(gwv6, false) 166 if err == nil { 167 n.Lock() 168 n.gwv6 = net.IP{} 169 n.Unlock() 170 } 171 172 return err 173 } 174 175 func (n *networkNamespace) AddStaticRoute(r *types.StaticRoute) error { 176 err := n.programRoute(n.nsPath(), r.Destination, r.NextHop) 177 if err == nil { 178 n.Lock() 179 n.staticRoutes = append(n.staticRoutes, r) 180 n.Unlock() 181 } 182 return err 183 } 184 185 func (n *networkNamespace) RemoveStaticRoute(r *types.StaticRoute) error { 186 err := n.removeRoute(n.nsPath(), r.Destination, r.NextHop) 187 if err == nil { 188 n.Lock() 189 lastIndex := len(n.staticRoutes) - 1 190 for i, v := range n.staticRoutes { 191 if v == r { 192 // Overwrite the route we're removing with the last element 193 n.staticRoutes[i] = n.staticRoutes[lastIndex] 194 // Shorten the slice to trim the extra element 195 n.staticRoutes = n.staticRoutes[:lastIndex] 196 break 197 } 198 } 199 n.Unlock() 200 } 201 return err 202 }