github.com/osrg/gobgp@v2.0.0+incompatible/cmd/gobgp/common.go (about) 1 // Copyright (C) 2015 Nippon Telegraph and Telephone Corporation. 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 12 // implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package main 17 18 import ( 19 "bytes" 20 "context" 21 "encoding/json" 22 "fmt" 23 "net" 24 "os" 25 "strconv" 26 "time" 27 28 "google.golang.org/grpc" 29 "google.golang.org/grpc/credentials" 30 31 api "github.com/osrg/gobgp/api" 32 "github.com/osrg/gobgp/pkg/packet/bgp" 33 ) 34 35 const globalRIBName = "global" 36 37 const ( 38 cmdGlobal = "global" 39 cmdNeighbor = "neighbor" 40 cmdPolicy = "policy" 41 cmdRib = "rib" 42 cmdAdd = "add" 43 cmdDel = "del" 44 cmdAll = "all" 45 cmdSet = "set" 46 cmdLocal = "local" 47 cmdAdjIn = "adj-in" 48 cmdAdjOut = "adj-out" 49 cmdReset = "reset" 50 cmdSoftReset = "softreset" 51 cmdSoftResetIn = "softresetin" 52 cmdSoftResetOut = "softresetout" 53 cmdShutdown = "shutdown" 54 cmdEnable = "enable" 55 cmdDisable = "disable" 56 cmdPrefix = "prefix" 57 cmdAspath = "as-path" 58 cmdCommunity = "community" 59 cmdExtcommunity = "ext-community" 60 cmdImport = "import" 61 cmdExport = "export" 62 cmdIn = "in" 63 cmdMonitor = "monitor" 64 cmdMRT = "mrt" 65 cmdInject = "inject" 66 cmdRPKI = "rpki" 67 cmdRPKITable = "table" 68 cmdRPKIServer = "server" 69 cmdVRF = "vrf" 70 cmdAccepted = "accepted" 71 cmdRejected = "rejected" 72 cmdStatement = "statement" 73 cmdCondition = "condition" 74 cmdAction = "action" 75 cmdUpdate = "update" 76 cmdBMP = "bmp" 77 cmdLargecommunity = "large-community" 78 cmdSummary = "summary" 79 ) 80 81 const ( 82 paramFlag = iota 83 paramSingle 84 paramList 85 ) 86 87 var subOpts struct { 88 AddressFamily string `short:"a" long:"address-family" description:"specifying an address family"` 89 } 90 91 var neighborsOpts struct { 92 Reason string `short:"r" long:"reason" description:"specifying communication field on Cease NOTIFICATION message with Administrative Shutdown subcode"` 93 Transport string `short:"t" long:"transport" description:"specifying a transport protocol"` 94 } 95 96 var mrtOpts struct { 97 Filename string `long:"filename" description:"MRT file name"` 98 RecordCount int64 `long:"count" description:"Number of records to inject"` 99 RecordSkip int64 `long:"skip" description:"Number of records to skip before injecting"` 100 QueueSize int `long:"batch-size" description:"Maximum number of updates to keep queued"` 101 Best bool `long:"only-best" description:"only keep best path routes"` 102 SkipV4 bool `long:"no-ipv4" description:"Skip importing IPv4 routes"` 103 SkipV6 bool `long:"no-ipv4" description:"Skip importing IPv6 routes"` 104 NextHop net.IP `long:"nexthop" description:"Rewrite nexthop"` 105 } 106 107 var bmpOpts struct { 108 StatisticsTimeout int `short:"s" long:"statistics-timeout" description:"Interval for Statistics Report"` 109 } 110 111 func formatTimedelta(t time.Time) string { 112 d := time.Now().Unix() - t.Unix() 113 u := uint64(d) 114 neg := d < 0 115 if neg { 116 u = -u 117 } 118 secs := u % 60 119 u /= 60 120 mins := u % 60 121 u /= 60 122 hours := u % 24 123 days := u / 24 124 125 if days == 0 { 126 return fmt.Sprintf("%02d:%02d:%02d", hours, mins, secs) 127 } 128 return fmt.Sprintf("%dd ", days) + fmt.Sprintf("%02d:%02d:%02d", hours, mins, secs) 129 } 130 131 func cidr2prefix(cidr string) string { 132 _, n, err := net.ParseCIDR(cidr) 133 if err != nil { 134 return cidr 135 } 136 var buffer bytes.Buffer 137 for i := 0; i < len(n.IP); i++ { 138 buffer.WriteString(fmt.Sprintf("%08b", n.IP[i])) 139 } 140 ones, _ := n.Mask.Size() 141 return buffer.String()[:ones] 142 } 143 144 func extractReserved(args []string, keys map[string]int) (map[string][]string, error) { 145 m := make(map[string][]string, len(keys)) 146 var k string 147 isReserved := func(s string) bool { 148 for r := range keys { 149 if s == r { 150 return true 151 } 152 } 153 return false 154 } 155 for _, arg := range args { 156 if isReserved(arg) { 157 k = arg 158 m[k] = make([]string, 0, 1) 159 } else { 160 m[k] = append(m[k], arg) 161 } 162 } 163 for k, v := range m { 164 if k == "" { 165 continue 166 } 167 switch keys[k] { 168 case paramFlag: 169 if len(v) != 0 { 170 return nil, fmt.Errorf("%s should not have arguments", k) 171 } 172 case paramSingle: 173 if len(v) != 1 { 174 return nil, fmt.Errorf("%s should have one argument", k) 175 } 176 case paramList: 177 if len(v) == 0 { 178 return nil, fmt.Errorf("%s should have one or more arguments", k) 179 } 180 } 181 } 182 return m, nil 183 } 184 185 func newClient(ctx context.Context) (api.GobgpApiClient, context.CancelFunc, error) { 186 grpcOpts := []grpc.DialOption{grpc.WithBlock()} 187 if globalOpts.TLS { 188 var creds credentials.TransportCredentials 189 if globalOpts.CaFile == "" { 190 creds = credentials.NewClientTLSFromCert(nil, "") 191 } else { 192 var err error 193 creds, err = credentials.NewClientTLSFromFile(globalOpts.CaFile, "") 194 if err != nil { 195 exitWithError(err) 196 } 197 } 198 grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(creds)) 199 } else { 200 grpcOpts = append(grpcOpts, grpc.WithInsecure()) 201 } 202 203 target := net.JoinHostPort(globalOpts.Host, strconv.Itoa(globalOpts.Port)) 204 if target == "" { 205 target = ":50051" 206 } 207 cc, cancel := context.WithTimeout(ctx, time.Second) 208 conn, err := grpc.DialContext(cc, target, grpcOpts...) 209 if err != nil { 210 return nil, cancel, err 211 } 212 return api.NewGobgpApiClient(conn), cancel, nil 213 } 214 215 func addr2AddressFamily(a net.IP) *api.Family { 216 if a.To4() != nil { 217 return &api.Family{ 218 Afi: api.Family_AFI_IP, 219 Safi: api.Family_SAFI_UNICAST, 220 } 221 } else if a.To16() != nil { 222 return &api.Family{ 223 Afi: api.Family_AFI_IP6, 224 Safi: api.Family_SAFI_UNICAST, 225 } 226 } 227 return nil 228 } 229 230 var ( 231 ipv4UC = &api.Family{ 232 Afi: api.Family_AFI_IP, 233 Safi: api.Family_SAFI_UNICAST, 234 } 235 ipv6UC = &api.Family{ 236 Afi: api.Family_AFI_IP6, 237 Safi: api.Family_SAFI_UNICAST, 238 } 239 ipv4VPN = &api.Family{ 240 Afi: api.Family_AFI_IP, 241 Safi: api.Family_SAFI_MPLS_VPN, 242 } 243 ipv6VPN = &api.Family{ 244 Afi: api.Family_AFI_IP6, 245 Safi: api.Family_SAFI_MPLS_VPN, 246 } 247 ipv4MPLS = &api.Family{ 248 Afi: api.Family_AFI_IP, 249 Safi: api.Family_SAFI_MPLS_LABEL, 250 } 251 ipv6MPLS = &api.Family{ 252 Afi: api.Family_AFI_IP6, 253 Safi: api.Family_SAFI_MPLS_LABEL, 254 } 255 evpn = &api.Family{ 256 Afi: api.Family_AFI_L2VPN, 257 Safi: api.Family_SAFI_EVPN, 258 } 259 ipv4Encap = &api.Family{ 260 Afi: api.Family_AFI_IP, 261 Safi: api.Family_SAFI_ENCAPSULATION, 262 } 263 ipv6Encap = &api.Family{ 264 Afi: api.Family_AFI_IP6, 265 Safi: api.Family_SAFI_ENCAPSULATION, 266 } 267 rtc = &api.Family{ 268 Afi: api.Family_AFI_IP, 269 Safi: api.Family_SAFI_ROUTE_TARGET_CONSTRAINTS, 270 } 271 ipv4Flowspec = &api.Family{ 272 Afi: api.Family_AFI_IP, 273 Safi: api.Family_SAFI_FLOW_SPEC_UNICAST, 274 } 275 ipv6Flowspec = &api.Family{ 276 Afi: api.Family_AFI_IP6, 277 Safi: api.Family_SAFI_FLOW_SPEC_UNICAST, 278 } 279 ipv4VPNflowspec = &api.Family{ 280 Afi: api.Family_AFI_IP, 281 Safi: api.Family_SAFI_FLOW_SPEC_VPN, 282 } 283 ipv6VPNflowspec = &api.Family{ 284 Afi: api.Family_AFI_IP6, 285 Safi: api.Family_SAFI_FLOW_SPEC_VPN, 286 } 287 l2VPNflowspec = &api.Family{ 288 Afi: api.Family_AFI_L2VPN, 289 Safi: api.Family_SAFI_FLOW_SPEC_VPN, 290 } 291 opaque = &api.Family{ 292 Afi: api.Family_AFI_OPAQUE, 293 Safi: api.Family_SAFI_KEY_VALUE, 294 } 295 ) 296 297 func checkAddressFamily(def *api.Family) (*api.Family, error) { 298 var f *api.Family 299 var e error 300 switch subOpts.AddressFamily { 301 case "ipv4", "v4", "4": 302 f = ipv4UC 303 case "ipv6", "v6", "6": 304 f = ipv6UC 305 case "ipv4-l3vpn", "vpnv4", "vpn-ipv4": 306 f = ipv4VPN 307 case "ipv6-l3vpn", "vpnv6", "vpn-ipv6": 308 f = ipv6VPN 309 case "ipv4-labeled", "ipv4-labelled", "ipv4-mpls": 310 f = ipv4MPLS 311 case "ipv6-labeled", "ipv6-labelled", "ipv6-mpls": 312 f = ipv6MPLS 313 case "evpn": 314 f = evpn 315 case "encap", "ipv4-encap": 316 f = ipv4Encap 317 case "ipv6-encap": 318 f = ipv6Encap 319 case "rtc": 320 f = rtc 321 case "ipv4-flowspec", "ipv4-flow", "flow4": 322 f = ipv4Flowspec 323 case "ipv6-flowspec", "ipv6-flow", "flow6": 324 f = ipv6Flowspec 325 case "ipv4-l3vpn-flowspec", "ipv4vpn-flowspec", "flowvpn4": 326 f = ipv4VPNflowspec 327 case "ipv6-l3vpn-flowspec", "ipv6vpn-flowspec", "flowvpn6": 328 f = ipv6VPNflowspec 329 case "l2vpn-flowspec": 330 f = l2VPNflowspec 331 case "opaque": 332 f = opaque 333 case "": 334 f = def 335 default: 336 e = fmt.Errorf("unsupported address family: %s", subOpts.AddressFamily) 337 } 338 return f, e 339 } 340 341 func printError(err error) { 342 if globalOpts.Json { 343 j, _ := json.Marshal(struct { 344 Error string `json:"error"` 345 }{Error: err.Error()}) 346 fmt.Println(string(j)) 347 } else { 348 fmt.Println(err) 349 } 350 } 351 352 func exitWithError(err error) { 353 printError(err) 354 os.Exit(1) 355 } 356 357 func getNextHopFromPathAttributes(attrs []bgp.PathAttributeInterface) net.IP { 358 for _, attr := range attrs { 359 switch a := attr.(type) { 360 case *bgp.PathAttributeNextHop: 361 return a.Value 362 case *bgp.PathAttributeMpReachNLRI: 363 return a.Nexthop 364 } 365 } 366 return nil 367 }