github.com/vishvananda/netlink@v1.3.1/route_linux.go (about) 1 package netlink 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "net" 9 "strconv" 10 "strings" 11 "syscall" 12 13 "github.com/vishvananda/netlink/nl" 14 "github.com/vishvananda/netns" 15 "golang.org/x/sys/unix" 16 ) 17 18 // RtAttr is shared so it is in netlink_linux.go 19 20 const ( 21 SCOPE_UNIVERSE Scope = unix.RT_SCOPE_UNIVERSE 22 SCOPE_SITE Scope = unix.RT_SCOPE_SITE 23 SCOPE_LINK Scope = unix.RT_SCOPE_LINK 24 SCOPE_HOST Scope = unix.RT_SCOPE_HOST 25 SCOPE_NOWHERE Scope = unix.RT_SCOPE_NOWHERE 26 ) 27 28 func (s Scope) String() string { 29 switch s { 30 case SCOPE_UNIVERSE: 31 return "universe" 32 case SCOPE_SITE: 33 return "site" 34 case SCOPE_LINK: 35 return "link" 36 case SCOPE_HOST: 37 return "host" 38 case SCOPE_NOWHERE: 39 return "nowhere" 40 default: 41 return "unknown" 42 } 43 } 44 45 const ( 46 FLAG_ONLINK NextHopFlag = unix.RTNH_F_ONLINK 47 FLAG_PERVASIVE NextHopFlag = unix.RTNH_F_PERVASIVE 48 ) 49 50 var testFlags = []flagString{ 51 {f: FLAG_ONLINK, s: "onlink"}, 52 {f: FLAG_PERVASIVE, s: "pervasive"}, 53 } 54 55 func listFlags(flag int) []string { 56 var flags []string 57 for _, tf := range testFlags { 58 if flag&int(tf.f) != 0 { 59 flags = append(flags, tf.s) 60 } 61 } 62 return flags 63 } 64 65 func (r *Route) ListFlags() []string { 66 return listFlags(r.Flags) 67 } 68 69 func (n *NexthopInfo) ListFlags() []string { 70 return listFlags(n.Flags) 71 } 72 73 type MPLSDestination struct { 74 Labels []int 75 } 76 77 func (d *MPLSDestination) Family() int { 78 return nl.FAMILY_MPLS 79 } 80 81 func (d *MPLSDestination) Decode(buf []byte) error { 82 d.Labels = nl.DecodeMPLSStack(buf) 83 return nil 84 } 85 86 func (d *MPLSDestination) Encode() ([]byte, error) { 87 return nl.EncodeMPLSStack(d.Labels...), nil 88 } 89 90 func (d *MPLSDestination) String() string { 91 s := make([]string, 0, len(d.Labels)) 92 for _, l := range d.Labels { 93 s = append(s, fmt.Sprintf("%d", l)) 94 } 95 return strings.Join(s, "/") 96 } 97 98 func (d *MPLSDestination) Equal(x Destination) bool { 99 o, ok := x.(*MPLSDestination) 100 if !ok { 101 return false 102 } 103 if d == nil && o == nil { 104 return true 105 } 106 if d == nil || o == nil { 107 return false 108 } 109 if d.Labels == nil && o.Labels == nil { 110 return true 111 } 112 if d.Labels == nil || o.Labels == nil { 113 return false 114 } 115 if len(d.Labels) != len(o.Labels) { 116 return false 117 } 118 for i := range d.Labels { 119 if d.Labels[i] != o.Labels[i] { 120 return false 121 } 122 } 123 return true 124 } 125 126 type MPLSEncap struct { 127 Labels []int 128 } 129 130 func (e *MPLSEncap) Type() int { 131 return nl.LWTUNNEL_ENCAP_MPLS 132 } 133 134 func (e *MPLSEncap) Decode(buf []byte) error { 135 if len(buf) < 4 { 136 return fmt.Errorf("lack of bytes") 137 } 138 l := native.Uint16(buf) 139 if len(buf) < int(l) { 140 return fmt.Errorf("lack of bytes") 141 } 142 buf = buf[:l] 143 typ := native.Uint16(buf[2:]) 144 if typ != nl.MPLS_IPTUNNEL_DST { 145 return fmt.Errorf("unknown MPLS Encap Type: %d", typ) 146 } 147 e.Labels = nl.DecodeMPLSStack(buf[4:]) 148 return nil 149 } 150 151 func (e *MPLSEncap) Encode() ([]byte, error) { 152 s := nl.EncodeMPLSStack(e.Labels...) 153 hdr := make([]byte, 4) 154 native.PutUint16(hdr, uint16(len(s)+4)) 155 native.PutUint16(hdr[2:], nl.MPLS_IPTUNNEL_DST) 156 return append(hdr, s...), nil 157 } 158 159 func (e *MPLSEncap) String() string { 160 s := make([]string, 0, len(e.Labels)) 161 for _, l := range e.Labels { 162 s = append(s, fmt.Sprintf("%d", l)) 163 } 164 return strings.Join(s, "/") 165 } 166 167 func (e *MPLSEncap) Equal(x Encap) bool { 168 o, ok := x.(*MPLSEncap) 169 if !ok { 170 return false 171 } 172 if e == nil && o == nil { 173 return true 174 } 175 if e == nil || o == nil { 176 return false 177 } 178 if e.Labels == nil && o.Labels == nil { 179 return true 180 } 181 if e.Labels == nil || o.Labels == nil { 182 return false 183 } 184 if len(e.Labels) != len(o.Labels) { 185 return false 186 } 187 for i := range e.Labels { 188 if e.Labels[i] != o.Labels[i] { 189 return false 190 } 191 } 192 return true 193 } 194 195 // SEG6 definitions 196 type SEG6Encap struct { 197 Mode int 198 Segments []net.IP 199 } 200 201 func (e *SEG6Encap) Type() int { 202 return nl.LWTUNNEL_ENCAP_SEG6 203 } 204 func (e *SEG6Encap) Decode(buf []byte) error { 205 if len(buf) < 4 { 206 return fmt.Errorf("lack of bytes") 207 } 208 // Get Length(l) & Type(typ) : 2 + 2 bytes 209 l := native.Uint16(buf) 210 if len(buf) < int(l) { 211 return fmt.Errorf("lack of bytes") 212 } 213 buf = buf[:l] // make sure buf size upper limit is Length 214 typ := native.Uint16(buf[2:]) 215 // LWTUNNEL_ENCAP_SEG6 has only one attr type SEG6_IPTUNNEL_SRH 216 if typ != nl.SEG6_IPTUNNEL_SRH { 217 return fmt.Errorf("unknown SEG6 Type: %d", typ) 218 } 219 220 var err error 221 e.Mode, e.Segments, err = nl.DecodeSEG6Encap(buf[4:]) 222 223 return err 224 } 225 func (e *SEG6Encap) Encode() ([]byte, error) { 226 s, err := nl.EncodeSEG6Encap(e.Mode, e.Segments) 227 hdr := make([]byte, 4) 228 native.PutUint16(hdr, uint16(len(s)+4)) 229 native.PutUint16(hdr[2:], nl.SEG6_IPTUNNEL_SRH) 230 return append(hdr, s...), err 231 } 232 func (e *SEG6Encap) String() string { 233 segs := make([]string, 0, len(e.Segments)) 234 // append segment backwards (from n to 0) since seg#0 is the last segment. 235 for i := len(e.Segments); i > 0; i-- { 236 segs = append(segs, e.Segments[i-1].String()) 237 } 238 str := fmt.Sprintf("mode %s segs %d [ %s ]", nl.SEG6EncapModeString(e.Mode), 239 len(e.Segments), strings.Join(segs, " ")) 240 return str 241 } 242 func (e *SEG6Encap) Equal(x Encap) bool { 243 o, ok := x.(*SEG6Encap) 244 if !ok { 245 return false 246 } 247 if e == o { 248 return true 249 } 250 if e == nil || o == nil { 251 return false 252 } 253 if e.Mode != o.Mode { 254 return false 255 } 256 if len(e.Segments) != len(o.Segments) { 257 return false 258 } 259 for i := range e.Segments { 260 if !e.Segments[i].Equal(o.Segments[i]) { 261 return false 262 } 263 } 264 return true 265 } 266 267 // SEG6LocalEncap definitions 268 type SEG6LocalEncap struct { 269 Flags [nl.SEG6_LOCAL_MAX]bool 270 Action int 271 Segments []net.IP // from SRH in seg6_local_lwt 272 Table int // table id for End.T and End.DT6 273 VrfTable int // vrftable id for END.DT4 and END.DT6 274 InAddr net.IP 275 In6Addr net.IP 276 Iif int 277 Oif int 278 bpf bpfObj 279 } 280 281 func (e *SEG6LocalEncap) SetProg(progFd int, progName string) error { 282 if progFd <= 0 { 283 return fmt.Errorf("seg6local bpf SetProg: invalid fd") 284 } 285 e.bpf.progFd = progFd 286 e.bpf.progName = progName 287 return nil 288 } 289 290 func (e *SEG6LocalEncap) Type() int { 291 return nl.LWTUNNEL_ENCAP_SEG6_LOCAL 292 } 293 func (e *SEG6LocalEncap) Decode(buf []byte) error { 294 attrs, err := nl.ParseRouteAttr(buf) 295 if err != nil { 296 return err 297 } 298 for _, attr := range attrs { 299 switch attr.Attr.Type { 300 case nl.SEG6_LOCAL_ACTION: 301 e.Action = int(native.Uint32(attr.Value[0:4])) 302 e.Flags[nl.SEG6_LOCAL_ACTION] = true 303 case nl.SEG6_LOCAL_SRH: 304 e.Segments, err = nl.DecodeSEG6Srh(attr.Value[:]) 305 e.Flags[nl.SEG6_LOCAL_SRH] = true 306 case nl.SEG6_LOCAL_TABLE: 307 e.Table = int(native.Uint32(attr.Value[0:4])) 308 e.Flags[nl.SEG6_LOCAL_TABLE] = true 309 case nl.SEG6_LOCAL_VRFTABLE: 310 e.VrfTable = int(native.Uint32(attr.Value[0:4])) 311 e.Flags[nl.SEG6_LOCAL_VRFTABLE] = true 312 case nl.SEG6_LOCAL_NH4: 313 e.InAddr = net.IP(attr.Value[0:4]) 314 e.Flags[nl.SEG6_LOCAL_NH4] = true 315 case nl.SEG6_LOCAL_NH6: 316 e.In6Addr = net.IP(attr.Value[0:16]) 317 e.Flags[nl.SEG6_LOCAL_NH6] = true 318 case nl.SEG6_LOCAL_IIF: 319 e.Iif = int(native.Uint32(attr.Value[0:4])) 320 e.Flags[nl.SEG6_LOCAL_IIF] = true 321 case nl.SEG6_LOCAL_OIF: 322 e.Oif = int(native.Uint32(attr.Value[0:4])) 323 e.Flags[nl.SEG6_LOCAL_OIF] = true 324 case nl.SEG6_LOCAL_BPF: 325 var bpfAttrs []syscall.NetlinkRouteAttr 326 bpfAttrs, err = nl.ParseRouteAttr(attr.Value) 327 bpfobj := bpfObj{} 328 for _, bpfAttr := range bpfAttrs { 329 switch bpfAttr.Attr.Type { 330 case nl.LWT_BPF_PROG_FD: 331 bpfobj.progFd = int(native.Uint32(bpfAttr.Value)) 332 case nl.LWT_BPF_PROG_NAME: 333 bpfobj.progName = string(bpfAttr.Value) 334 default: 335 err = fmt.Errorf("seg6local bpf decode: unknown attribute: Type %d", bpfAttr.Attr) 336 } 337 } 338 e.bpf = bpfobj 339 e.Flags[nl.SEG6_LOCAL_BPF] = true 340 } 341 } 342 return err 343 } 344 func (e *SEG6LocalEncap) Encode() ([]byte, error) { 345 var err error 346 res := make([]byte, 8) 347 native.PutUint16(res, 8) // length 348 native.PutUint16(res[2:], nl.SEG6_LOCAL_ACTION) 349 native.PutUint32(res[4:], uint32(e.Action)) 350 if e.Flags[nl.SEG6_LOCAL_SRH] { 351 srh, err := nl.EncodeSEG6Srh(e.Segments) 352 if err != nil { 353 return nil, err 354 } 355 attr := make([]byte, 4) 356 native.PutUint16(attr, uint16(len(srh)+4)) 357 native.PutUint16(attr[2:], nl.SEG6_LOCAL_SRH) 358 attr = append(attr, srh...) 359 res = append(res, attr...) 360 } 361 if e.Flags[nl.SEG6_LOCAL_TABLE] { 362 attr := make([]byte, 8) 363 native.PutUint16(attr, 8) 364 native.PutUint16(attr[2:], nl.SEG6_LOCAL_TABLE) 365 native.PutUint32(attr[4:], uint32(e.Table)) 366 res = append(res, attr...) 367 } 368 369 if e.Flags[nl.SEG6_LOCAL_VRFTABLE] { 370 attr := make([]byte, 8) 371 native.PutUint16(attr, 8) 372 native.PutUint16(attr[2:], nl.SEG6_LOCAL_VRFTABLE) 373 native.PutUint32(attr[4:], uint32(e.VrfTable)) 374 res = append(res, attr...) 375 } 376 377 if e.Flags[nl.SEG6_LOCAL_NH4] { 378 attr := make([]byte, 4) 379 native.PutUint16(attr, 8) 380 native.PutUint16(attr[2:], nl.SEG6_LOCAL_NH4) 381 ipv4 := e.InAddr.To4() 382 if ipv4 == nil { 383 err = fmt.Errorf("SEG6_LOCAL_NH4 has invalid IPv4 address") 384 return nil, err 385 } 386 attr = append(attr, ipv4...) 387 res = append(res, attr...) 388 } 389 if e.Flags[nl.SEG6_LOCAL_NH6] { 390 attr := make([]byte, 4) 391 native.PutUint16(attr, 20) 392 native.PutUint16(attr[2:], nl.SEG6_LOCAL_NH6) 393 attr = append(attr, e.In6Addr...) 394 res = append(res, attr...) 395 } 396 if e.Flags[nl.SEG6_LOCAL_IIF] { 397 attr := make([]byte, 8) 398 native.PutUint16(attr, 8) 399 native.PutUint16(attr[2:], nl.SEG6_LOCAL_IIF) 400 native.PutUint32(attr[4:], uint32(e.Iif)) 401 res = append(res, attr...) 402 } 403 if e.Flags[nl.SEG6_LOCAL_OIF] { 404 attr := make([]byte, 8) 405 native.PutUint16(attr, 8) 406 native.PutUint16(attr[2:], nl.SEG6_LOCAL_OIF) 407 native.PutUint32(attr[4:], uint32(e.Oif)) 408 res = append(res, attr...) 409 } 410 if e.Flags[nl.SEG6_LOCAL_BPF] { 411 attr := nl.NewRtAttr(nl.SEG6_LOCAL_BPF, []byte{}) 412 if e.bpf.progFd != 0 { 413 attr.AddRtAttr(nl.LWT_BPF_PROG_FD, nl.Uint32Attr(uint32(e.bpf.progFd))) 414 } 415 if e.bpf.progName != "" { 416 attr.AddRtAttr(nl.LWT_BPF_PROG_NAME, nl.ZeroTerminated(e.bpf.progName)) 417 } 418 res = append(res, attr.Serialize()...) 419 } 420 return res, err 421 } 422 func (e *SEG6LocalEncap) String() string { 423 strs := make([]string, 0, nl.SEG6_LOCAL_MAX) 424 strs = append(strs, fmt.Sprintf("action %s", nl.SEG6LocalActionString(e.Action))) 425 426 if e.Flags[nl.SEG6_LOCAL_TABLE] { 427 strs = append(strs, fmt.Sprintf("table %d", e.Table)) 428 } 429 430 if e.Flags[nl.SEG6_LOCAL_VRFTABLE] { 431 strs = append(strs, fmt.Sprintf("vrftable %d", e.VrfTable)) 432 } 433 434 if e.Flags[nl.SEG6_LOCAL_NH4] { 435 strs = append(strs, fmt.Sprintf("nh4 %s", e.InAddr)) 436 } 437 if e.Flags[nl.SEG6_LOCAL_NH6] { 438 strs = append(strs, fmt.Sprintf("nh6 %s", e.In6Addr)) 439 } 440 if e.Flags[nl.SEG6_LOCAL_IIF] { 441 link, err := LinkByIndex(e.Iif) 442 if err != nil { 443 strs = append(strs, fmt.Sprintf("iif %d", e.Iif)) 444 } else { 445 strs = append(strs, fmt.Sprintf("iif %s", link.Attrs().Name)) 446 } 447 } 448 if e.Flags[nl.SEG6_LOCAL_OIF] { 449 link, err := LinkByIndex(e.Oif) 450 if err != nil { 451 strs = append(strs, fmt.Sprintf("oif %d", e.Oif)) 452 } else { 453 strs = append(strs, fmt.Sprintf("oif %s", link.Attrs().Name)) 454 } 455 } 456 if e.Flags[nl.SEG6_LOCAL_SRH] { 457 segs := make([]string, 0, len(e.Segments)) 458 // append segment backwards (from n to 0) since seg#0 is the last segment. 459 for i := len(e.Segments); i > 0; i-- { 460 segs = append(segs, e.Segments[i-1].String()) 461 } 462 strs = append(strs, fmt.Sprintf("segs %d [ %s ]", len(e.Segments), strings.Join(segs, " "))) 463 } 464 if e.Flags[nl.SEG6_LOCAL_BPF] { 465 strs = append(strs, fmt.Sprintf("bpf %s[%d]", e.bpf.progName, e.bpf.progFd)) 466 } 467 return strings.Join(strs, " ") 468 } 469 func (e *SEG6LocalEncap) Equal(x Encap) bool { 470 o, ok := x.(*SEG6LocalEncap) 471 if !ok { 472 return false 473 } 474 if e == o { 475 return true 476 } 477 if e == nil || o == nil { 478 return false 479 } 480 // compare all arrays first 481 for i := range e.Flags { 482 if e.Flags[i] != o.Flags[i] { 483 return false 484 } 485 } 486 if len(e.Segments) != len(o.Segments) { 487 return false 488 } 489 for i := range e.Segments { 490 if !e.Segments[i].Equal(o.Segments[i]) { 491 return false 492 } 493 } 494 // compare values 495 if !e.InAddr.Equal(o.InAddr) || !e.In6Addr.Equal(o.In6Addr) { 496 return false 497 } 498 if e.Action != o.Action || e.Table != o.Table || e.Iif != o.Iif || e.Oif != o.Oif || e.bpf != o.bpf || e.VrfTable != o.VrfTable { 499 return false 500 } 501 return true 502 } 503 504 // Encap BPF definitions 505 type bpfObj struct { 506 progFd int 507 progName string 508 } 509 type BpfEncap struct { 510 progs [nl.LWT_BPF_MAX]bpfObj 511 headroom int 512 } 513 514 // SetProg adds a bpf function to the route via netlink RTA_ENCAP. The fd must be a bpf 515 // program loaded with bpf(type=BPF_PROG_TYPE_LWT_*) matching the direction the program should 516 // be applied to (LWT_BPF_IN, LWT_BPF_OUT, LWT_BPF_XMIT). 517 func (e *BpfEncap) SetProg(mode, progFd int, progName string) error { 518 if progFd <= 0 { 519 return fmt.Errorf("lwt bpf SetProg: invalid fd") 520 } 521 if mode <= nl.LWT_BPF_UNSPEC || mode >= nl.LWT_BPF_XMIT_HEADROOM { 522 return fmt.Errorf("lwt bpf SetProg:invalid mode") 523 } 524 e.progs[mode].progFd = progFd 525 e.progs[mode].progName = fmt.Sprintf("%s[fd:%d]", progName, progFd) 526 return nil 527 } 528 529 // SetXmitHeadroom sets the xmit headroom (LWT_BPF_MAX_HEADROOM) via netlink RTA_ENCAP. 530 // maximum headroom is LWT_BPF_MAX_HEADROOM 531 func (e *BpfEncap) SetXmitHeadroom(headroom int) error { 532 if headroom > nl.LWT_BPF_MAX_HEADROOM || headroom < 0 { 533 return fmt.Errorf("invalid headroom size. range is 0 - %d", nl.LWT_BPF_MAX_HEADROOM) 534 } 535 e.headroom = headroom 536 return nil 537 } 538 539 func (e *BpfEncap) Type() int { 540 return nl.LWTUNNEL_ENCAP_BPF 541 } 542 func (e *BpfEncap) Decode(buf []byte) error { 543 if len(buf) < 4 { 544 return fmt.Errorf("lwt bpf decode: lack of bytes") 545 } 546 native := nl.NativeEndian() 547 attrs, err := nl.ParseRouteAttr(buf) 548 if err != nil { 549 return fmt.Errorf("lwt bpf decode: failed parsing attribute. err: %v", err) 550 } 551 for _, attr := range attrs { 552 if int(attr.Attr.Type) < 1 { 553 // nl.LWT_BPF_UNSPEC 554 continue 555 } 556 if int(attr.Attr.Type) > nl.LWT_BPF_MAX { 557 return fmt.Errorf("lwt bpf decode: received unknown attribute type: %d", attr.Attr.Type) 558 } 559 switch int(attr.Attr.Type) { 560 case nl.LWT_BPF_MAX_HEADROOM: 561 e.headroom = int(native.Uint32(attr.Value)) 562 default: 563 bpfO := bpfObj{} 564 parsedAttrs, err := nl.ParseRouteAttr(attr.Value) 565 if err != nil { 566 return fmt.Errorf("lwt bpf decode: failed parsing route attribute") 567 } 568 for _, parsedAttr := range parsedAttrs { 569 switch int(parsedAttr.Attr.Type) { 570 case nl.LWT_BPF_PROG_FD: 571 bpfO.progFd = int(native.Uint32(parsedAttr.Value)) 572 case nl.LWT_BPF_PROG_NAME: 573 bpfO.progName = string(parsedAttr.Value) 574 default: 575 return fmt.Errorf("lwt bpf decode: received unknown attribute: type: %d, len: %d", parsedAttr.Attr.Type, parsedAttr.Attr.Len) 576 } 577 } 578 e.progs[attr.Attr.Type] = bpfO 579 } 580 } 581 return nil 582 } 583 584 func (e *BpfEncap) Encode() ([]byte, error) { 585 buf := make([]byte, 0) 586 native = nl.NativeEndian() 587 for index, attr := range e.progs { 588 nlMsg := nl.NewRtAttr(index, []byte{}) 589 if attr.progFd != 0 { 590 nlMsg.AddRtAttr(nl.LWT_BPF_PROG_FD, nl.Uint32Attr(uint32(attr.progFd))) 591 } 592 if attr.progName != "" { 593 nlMsg.AddRtAttr(nl.LWT_BPF_PROG_NAME, nl.ZeroTerminated(attr.progName)) 594 } 595 if nlMsg.Len() > 4 { 596 buf = append(buf, nlMsg.Serialize()...) 597 } 598 } 599 if len(buf) <= 4 { 600 return nil, fmt.Errorf("lwt bpf encode: bpf obj definitions returned empty buffer") 601 } 602 if e.headroom > 0 { 603 hRoom := nl.NewRtAttr(nl.LWT_BPF_XMIT_HEADROOM, nl.Uint32Attr(uint32(e.headroom))) 604 buf = append(buf, hRoom.Serialize()...) 605 } 606 return buf, nil 607 } 608 609 func (e *BpfEncap) String() string { 610 progs := make([]string, 0) 611 for index, obj := range e.progs { 612 empty := bpfObj{} 613 switch index { 614 case nl.LWT_BPF_IN: 615 if obj != empty { 616 progs = append(progs, fmt.Sprintf("in: %s", obj.progName)) 617 } 618 case nl.LWT_BPF_OUT: 619 if obj != empty { 620 progs = append(progs, fmt.Sprintf("out: %s", obj.progName)) 621 } 622 case nl.LWT_BPF_XMIT: 623 if obj != empty { 624 progs = append(progs, fmt.Sprintf("xmit: %s", obj.progName)) 625 } 626 } 627 } 628 if e.headroom > 0 { 629 progs = append(progs, fmt.Sprintf("xmit headroom: %d", e.headroom)) 630 } 631 return strings.Join(progs, " ") 632 } 633 634 func (e *BpfEncap) Equal(x Encap) bool { 635 o, ok := x.(*BpfEncap) 636 if !ok { 637 return false 638 } 639 if e.headroom != o.headroom { 640 return false 641 } 642 for i := range o.progs { 643 if o.progs[i] != e.progs[i] { 644 return false 645 } 646 } 647 return true 648 } 649 650 // IP6tnlEncap definition 651 type IP6tnlEncap struct { 652 ID uint64 653 Dst net.IP 654 Src net.IP 655 Hoplimit uint8 656 TC uint8 657 Flags uint16 658 } 659 660 func (e *IP6tnlEncap) Type() int { 661 return nl.LWTUNNEL_ENCAP_IP6 662 } 663 664 func (e *IP6tnlEncap) Decode(buf []byte) error { 665 attrs, err := nl.ParseRouteAttr(buf) 666 if err != nil { 667 return err 668 } 669 for _, attr := range attrs { 670 switch attr.Attr.Type { 671 case nl.LWTUNNEL_IP6_ID: 672 e.ID = uint64(native.Uint64(attr.Value[0:4])) 673 case nl.LWTUNNEL_IP6_DST: 674 e.Dst = net.IP(attr.Value[:]) 675 case nl.LWTUNNEL_IP6_SRC: 676 e.Src = net.IP(attr.Value[:]) 677 case nl.LWTUNNEL_IP6_HOPLIMIT: 678 e.Hoplimit = attr.Value[0] 679 case nl.LWTUNNEL_IP6_TC: 680 // e.TC = attr.Value[0] 681 err = fmt.Errorf("decoding TC in IP6tnlEncap is not supported") 682 case nl.LWTUNNEL_IP6_FLAGS: 683 // e.Flags = uint16(native.Uint16(attr.Value[0:2])) 684 err = fmt.Errorf("decoding FLAG in IP6tnlEncap is not supported") 685 case nl.LWTUNNEL_IP6_PAD: 686 err = fmt.Errorf("decoding PAD in IP6tnlEncap is not supported") 687 case nl.LWTUNNEL_IP6_OPTS: 688 err = fmt.Errorf("decoding OPTS in IP6tnlEncap is not supported") 689 } 690 } 691 return err 692 } 693 694 func (e *IP6tnlEncap) Encode() ([]byte, error) { 695 696 final := []byte{} 697 698 resID := make([]byte, 12) 699 native.PutUint16(resID, 12) // 2+2+8 700 native.PutUint16(resID[2:], nl.LWTUNNEL_IP6_ID) 701 native.PutUint64(resID[4:], 0) 702 final = append(final, resID...) 703 704 resDst := make([]byte, 4) 705 native.PutUint16(resDst, 20) // 2+2+16 706 native.PutUint16(resDst[2:], nl.LWTUNNEL_IP6_DST) 707 resDst = append(resDst, e.Dst...) 708 final = append(final, resDst...) 709 710 resSrc := make([]byte, 4) 711 native.PutUint16(resSrc, 20) 712 native.PutUint16(resSrc[2:], nl.LWTUNNEL_IP6_SRC) 713 resSrc = append(resSrc, e.Src...) 714 final = append(final, resSrc...) 715 716 // resTc := make([]byte, 5) 717 // native.PutUint16(resTc, 5) 718 // native.PutUint16(resTc[2:], nl.LWTUNNEL_IP6_TC) 719 // resTc[4] = e.TC 720 // final = append(final,resTc...) 721 722 resHops := make([]byte, 5) 723 native.PutUint16(resHops, 5) 724 native.PutUint16(resHops[2:], nl.LWTUNNEL_IP6_HOPLIMIT) 725 resHops[4] = e.Hoplimit 726 final = append(final, resHops...) 727 728 // resFlags := make([]byte, 6) 729 // native.PutUint16(resFlags, 6) 730 // native.PutUint16(resFlags[2:], nl.LWTUNNEL_IP6_FLAGS) 731 // native.PutUint16(resFlags[4:], e.Flags) 732 // final = append(final,resFlags...) 733 734 return final, nil 735 } 736 737 func (e *IP6tnlEncap) String() string { 738 return fmt.Sprintf("id %d src %s dst %s hoplimit %d tc %d flags 0x%.4x", e.ID, e.Src, e.Dst, e.Hoplimit, e.TC, e.Flags) 739 } 740 741 func (e *IP6tnlEncap) Equal(x Encap) bool { 742 o, ok := x.(*IP6tnlEncap) 743 if !ok { 744 return false 745 } 746 747 if e.ID != o.ID || e.Flags != o.Flags || e.Hoplimit != o.Hoplimit || e.Src.Equal(o.Src) || e.Dst.Equal(o.Dst) || e.TC != o.TC { 748 return false 749 } 750 return true 751 } 752 753 type Via struct { 754 AddrFamily int 755 Addr net.IP 756 } 757 758 func (v *Via) Equal(x Destination) bool { 759 o, ok := x.(*Via) 760 if !ok { 761 return false 762 } 763 if v.AddrFamily == x.Family() && v.Addr.Equal(o.Addr) { 764 return true 765 } 766 return false 767 } 768 769 func (v *Via) String() string { 770 return fmt.Sprintf("Family: %d, Address: %s", v.AddrFamily, v.Addr.String()) 771 } 772 773 func (v *Via) Family() int { 774 return v.AddrFamily 775 } 776 777 func (v *Via) Encode() ([]byte, error) { 778 buf := &bytes.Buffer{} 779 err := binary.Write(buf, native, uint16(v.AddrFamily)) 780 if err != nil { 781 return nil, err 782 } 783 err = binary.Write(buf, native, v.Addr) 784 if err != nil { 785 return nil, err 786 } 787 return buf.Bytes(), nil 788 } 789 790 func (v *Via) Decode(b []byte) error { 791 if len(b) < 6 { 792 return fmt.Errorf("decoding failed: buffer too small (%d bytes)", len(b)) 793 } 794 v.AddrFamily = int(native.Uint16(b[0:2])) 795 if v.AddrFamily == nl.FAMILY_V4 { 796 v.Addr = net.IP(b[2:6]) 797 return nil 798 } else if v.AddrFamily == nl.FAMILY_V6 { 799 if len(b) < 18 { 800 return fmt.Errorf("decoding failed: buffer too small (%d bytes)", len(b)) 801 } 802 v.Addr = net.IP(b[2:]) 803 return nil 804 } 805 return fmt.Errorf("decoding failed: address family %d unknown", v.AddrFamily) 806 } 807 808 // RouteAdd will add a route to the system. 809 // Equivalent to: `ip route add $route` 810 func RouteAdd(route *Route) error { 811 return pkgHandle.RouteAdd(route) 812 } 813 814 // RouteAdd will add a route to the system. 815 // Equivalent to: `ip route add $route` 816 func (h *Handle) RouteAdd(route *Route) error { 817 flags := unix.NLM_F_CREATE | unix.NLM_F_EXCL | unix.NLM_F_ACK 818 req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags) 819 _, err := h.routeHandle(route, req, nl.NewRtMsg()) 820 return err 821 } 822 823 // RouteAppend will append a route to the system. 824 // Equivalent to: `ip route append $route` 825 func RouteAppend(route *Route) error { 826 return pkgHandle.RouteAppend(route) 827 } 828 829 // RouteAppend will append a route to the system. 830 // Equivalent to: `ip route append $route` 831 func (h *Handle) RouteAppend(route *Route) error { 832 flags := unix.NLM_F_CREATE | unix.NLM_F_APPEND | unix.NLM_F_ACK 833 req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags) 834 _, err := h.routeHandle(route, req, nl.NewRtMsg()) 835 return err 836 } 837 838 // RouteAddEcmp will add a route to the system. 839 func RouteAddEcmp(route *Route) error { 840 return pkgHandle.RouteAddEcmp(route) 841 } 842 843 // RouteAddEcmp will add a route to the system. 844 func (h *Handle) RouteAddEcmp(route *Route) error { 845 flags := unix.NLM_F_CREATE | unix.NLM_F_ACK 846 req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags) 847 _, err := h.routeHandle(route, req, nl.NewRtMsg()) 848 return err 849 } 850 851 // RouteChange will change an existing route in the system. 852 // Equivalent to: `ip route change $route` 853 func RouteChange(route *Route) error { 854 return pkgHandle.RouteChange(route) 855 } 856 857 // RouteChange will change an existing route in the system. 858 // Equivalent to: `ip route change $route` 859 func (h *Handle) RouteChange(route *Route) error { 860 flags := unix.NLM_F_REPLACE | unix.NLM_F_ACK 861 req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags) 862 _, err := h.routeHandle(route, req, nl.NewRtMsg()) 863 return err 864 } 865 866 // RouteReplace will add a route to the system. 867 // Equivalent to: `ip route replace $route` 868 func RouteReplace(route *Route) error { 869 return pkgHandle.RouteReplace(route) 870 } 871 872 // RouteReplace will add a route to the system. 873 // Equivalent to: `ip route replace $route` 874 func (h *Handle) RouteReplace(route *Route) error { 875 flags := unix.NLM_F_CREATE | unix.NLM_F_REPLACE | unix.NLM_F_ACK 876 req := h.newNetlinkRequest(unix.RTM_NEWROUTE, flags) 877 _, err := h.routeHandle(route, req, nl.NewRtMsg()) 878 return err 879 } 880 881 // RouteDel will delete a route from the system. 882 // Equivalent to: `ip route del $route` 883 func RouteDel(route *Route) error { 884 return pkgHandle.RouteDel(route) 885 } 886 887 // RouteDel will delete a route from the system. 888 // Equivalent to: `ip route del $route` 889 func (h *Handle) RouteDel(route *Route) error { 890 req := h.newNetlinkRequest(unix.RTM_DELROUTE, unix.NLM_F_ACK) 891 _, err := h.routeHandle(route, req, nl.NewRtDelMsg()) 892 return err 893 } 894 895 func (h *Handle) routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) ([][]byte, error) { 896 if err := h.prepareRouteReq(route, req, msg); err != nil { 897 return nil, err 898 } 899 return req.Execute(unix.NETLINK_ROUTE, 0) 900 } 901 902 func (h *Handle) routeHandleIter(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg, f func(msg []byte) bool) error { 903 if err := h.prepareRouteReq(route, req, msg); err != nil { 904 return err 905 } 906 return req.ExecuteIter(unix.NETLINK_ROUTE, 0, f) 907 } 908 909 func (h *Handle) prepareRouteReq(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error { 910 if req.NlMsghdr.Type != unix.RTM_GETROUTE && (route.Dst == nil || route.Dst.IP == nil) && route.Src == nil && route.Gw == nil && route.MPLSDst == nil { 911 return fmt.Errorf("either Dst.IP, Src.IP or Gw must be set") 912 } 913 914 family := -1 915 var rtAttrs []*nl.RtAttr 916 917 if route.Dst != nil && route.Dst.IP != nil { 918 dstLen, _ := route.Dst.Mask.Size() 919 msg.Dst_len = uint8(dstLen) 920 dstFamily := nl.GetIPFamily(route.Dst.IP) 921 family = dstFamily 922 var dstData []byte 923 if dstFamily == FAMILY_V4 { 924 dstData = route.Dst.IP.To4() 925 } else { 926 dstData = route.Dst.IP.To16() 927 } 928 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, dstData)) 929 } else if route.MPLSDst != nil { 930 family = nl.FAMILY_MPLS 931 msg.Dst_len = uint8(20) 932 msg.Type = unix.RTN_UNICAST 933 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_DST, nl.EncodeMPLSStack(*route.MPLSDst))) 934 } 935 936 if route.NewDst != nil { 937 if family != -1 && family != route.NewDst.Family() { 938 return fmt.Errorf("new destination and destination are not the same address family") 939 } 940 buf, err := route.NewDst.Encode() 941 if err != nil { 942 return err 943 } 944 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_NEWDST, buf)) 945 } 946 947 if route.Encap != nil { 948 buf := make([]byte, 2) 949 native.PutUint16(buf, uint16(route.Encap.Type())) 950 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP_TYPE, buf)) 951 buf, err := route.Encap.Encode() 952 if err != nil { 953 return err 954 } 955 switch route.Encap.Type() { 956 case nl.LWTUNNEL_ENCAP_BPF: 957 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP|unix.NLA_F_NESTED, buf)) 958 default: 959 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_ENCAP, buf)) 960 } 961 962 } 963 964 if route.Src != nil { 965 srcFamily := nl.GetIPFamily(route.Src) 966 if family != -1 && family != srcFamily { 967 return fmt.Errorf("source and destination ip are not the same IP family") 968 } 969 family = srcFamily 970 var srcData []byte 971 if srcFamily == FAMILY_V4 { 972 srcData = route.Src.To4() 973 } else { 974 srcData = route.Src.To16() 975 } 976 // The commonly used src ip for routes is actually PREFSRC 977 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PREFSRC, srcData)) 978 } 979 980 if route.Gw != nil { 981 gwFamily := nl.GetIPFamily(route.Gw) 982 if family != -1 && family != gwFamily { 983 return fmt.Errorf("gateway, source, and destination ip are not the same IP family") 984 } 985 family = gwFamily 986 var gwData []byte 987 if gwFamily == FAMILY_V4 { 988 gwData = route.Gw.To4() 989 } else { 990 gwData = route.Gw.To16() 991 } 992 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_GATEWAY, gwData)) 993 } 994 995 if route.Via != nil { 996 buf, err := route.Via.Encode() 997 if err != nil { 998 return fmt.Errorf("failed to encode RTA_VIA: %v", err) 999 } 1000 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_VIA, buf)) 1001 } 1002 1003 if len(route.MultiPath) > 0 { 1004 buf := []byte{} 1005 for _, nh := range route.MultiPath { 1006 rtnh := &nl.RtNexthop{ 1007 RtNexthop: unix.RtNexthop{ 1008 Hops: uint8(nh.Hops), 1009 Ifindex: int32(nh.LinkIndex), 1010 Flags: uint8(nh.Flags), 1011 }, 1012 } 1013 children := []nl.NetlinkRequestData{} 1014 if nh.Gw != nil { 1015 gwFamily := nl.GetIPFamily(nh.Gw) 1016 if family != -1 && family != gwFamily { 1017 return fmt.Errorf("gateway, source, and destination ip are not the same IP family") 1018 } 1019 if gwFamily == FAMILY_V4 { 1020 children = append(children, nl.NewRtAttr(unix.RTA_GATEWAY, []byte(nh.Gw.To4()))) 1021 } else { 1022 children = append(children, nl.NewRtAttr(unix.RTA_GATEWAY, []byte(nh.Gw.To16()))) 1023 } 1024 } 1025 if nh.NewDst != nil { 1026 if family != -1 && family != nh.NewDst.Family() { 1027 return fmt.Errorf("new destination and destination are not the same address family") 1028 } 1029 buf, err := nh.NewDst.Encode() 1030 if err != nil { 1031 return err 1032 } 1033 children = append(children, nl.NewRtAttr(unix.RTA_NEWDST, buf)) 1034 } 1035 if nh.Encap != nil { 1036 buf := make([]byte, 2) 1037 native.PutUint16(buf, uint16(nh.Encap.Type())) 1038 children = append(children, nl.NewRtAttr(unix.RTA_ENCAP_TYPE, buf)) 1039 buf, err := nh.Encap.Encode() 1040 if err != nil { 1041 return err 1042 } 1043 children = append(children, nl.NewRtAttr(unix.RTA_ENCAP, buf)) 1044 } 1045 if nh.Via != nil { 1046 buf, err := nh.Via.Encode() 1047 if err != nil { 1048 return err 1049 } 1050 children = append(children, nl.NewRtAttr(unix.RTA_VIA, buf)) 1051 } 1052 rtnh.Children = children 1053 buf = append(buf, rtnh.Serialize()...) 1054 } 1055 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_MULTIPATH, buf)) 1056 } 1057 1058 if route.Table > 0 { 1059 if route.Table >= 256 { 1060 msg.Table = unix.RT_TABLE_UNSPEC 1061 b := make([]byte, 4) 1062 native.PutUint32(b, uint32(route.Table)) 1063 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_TABLE, b)) 1064 } else { 1065 msg.Table = uint8(route.Table) 1066 } 1067 } 1068 1069 if route.Priority > 0 { 1070 b := make([]byte, 4) 1071 native.PutUint32(b, uint32(route.Priority)) 1072 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_PRIORITY, b)) 1073 } 1074 if route.Realm > 0 { 1075 b := make([]byte, 4) 1076 native.PutUint32(b, uint32(route.Realm)) 1077 rtAttrs = append(rtAttrs, nl.NewRtAttr(unix.RTA_FLOW, b)) 1078 } 1079 if route.Tos > 0 { 1080 msg.Tos = uint8(route.Tos) 1081 } 1082 if route.Protocol > 0 { 1083 msg.Protocol = uint8(route.Protocol) 1084 } 1085 if route.Type > 0 { 1086 msg.Type = uint8(route.Type) 1087 } 1088 1089 var metrics []*nl.RtAttr 1090 if route.MTU > 0 { 1091 b := nl.Uint32Attr(uint32(route.MTU)) 1092 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_MTU, b)) 1093 if route.MTULock { 1094 b := nl.Uint32Attr(uint32(1 << unix.RTAX_MTU)) 1095 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_LOCK, b)) 1096 } 1097 } 1098 if route.Window > 0 { 1099 b := nl.Uint32Attr(uint32(route.Window)) 1100 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_WINDOW, b)) 1101 } 1102 if route.Rtt > 0 { 1103 b := nl.Uint32Attr(uint32(route.Rtt)) 1104 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_RTT, b)) 1105 } 1106 if route.RttVar > 0 { 1107 b := nl.Uint32Attr(uint32(route.RttVar)) 1108 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_RTTVAR, b)) 1109 } 1110 if route.Ssthresh > 0 { 1111 b := nl.Uint32Attr(uint32(route.Ssthresh)) 1112 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_SSTHRESH, b)) 1113 } 1114 if route.Cwnd > 0 { 1115 b := nl.Uint32Attr(uint32(route.Cwnd)) 1116 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_CWND, b)) 1117 } 1118 if route.AdvMSS > 0 { 1119 b := nl.Uint32Attr(uint32(route.AdvMSS)) 1120 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_ADVMSS, b)) 1121 } 1122 if route.Reordering > 0 { 1123 b := nl.Uint32Attr(uint32(route.Reordering)) 1124 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_REORDERING, b)) 1125 } 1126 if route.Hoplimit > 0 { 1127 b := nl.Uint32Attr(uint32(route.Hoplimit)) 1128 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_HOPLIMIT, b)) 1129 } 1130 if route.InitCwnd > 0 { 1131 b := nl.Uint32Attr(uint32(route.InitCwnd)) 1132 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_INITCWND, b)) 1133 } 1134 if route.Features > 0 { 1135 b := nl.Uint32Attr(uint32(route.Features)) 1136 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_FEATURES, b)) 1137 } 1138 if route.RtoMin > 0 { 1139 b := nl.Uint32Attr(uint32(route.RtoMin)) 1140 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_RTO_MIN, b)) 1141 if route.RtoMinLock { 1142 b := nl.Uint32Attr(uint32(1 << unix.RTAX_RTO_MIN)) 1143 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_LOCK, b)) 1144 } 1145 } 1146 if route.InitRwnd > 0 { 1147 b := nl.Uint32Attr(uint32(route.InitRwnd)) 1148 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_INITRWND, b)) 1149 } 1150 if route.QuickACK > 0 { 1151 b := nl.Uint32Attr(uint32(route.QuickACK)) 1152 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_QUICKACK, b)) 1153 } 1154 if route.Congctl != "" { 1155 b := nl.ZeroTerminated(route.Congctl) 1156 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_CC_ALGO, b)) 1157 } 1158 if route.FastOpenNoCookie > 0 { 1159 b := nl.Uint32Attr(uint32(route.FastOpenNoCookie)) 1160 metrics = append(metrics, nl.NewRtAttr(unix.RTAX_FASTOPEN_NO_COOKIE, b)) 1161 } 1162 1163 if metrics != nil { 1164 attr := nl.NewRtAttr(unix.RTA_METRICS, nil) 1165 for _, metric := range metrics { 1166 attr.AddChild(metric) 1167 } 1168 rtAttrs = append(rtAttrs, attr) 1169 } 1170 1171 msg.Flags = uint32(route.Flags) 1172 msg.Scope = uint8(route.Scope) 1173 // only overwrite family if it was not set in msg 1174 if msg.Family == 0 { 1175 msg.Family = uint8(family) 1176 } 1177 req.AddData(msg) 1178 for _, attr := range rtAttrs { 1179 req.AddData(attr) 1180 } 1181 1182 if (req.NlMsghdr.Type != unix.RTM_GETROUTE) || (req.NlMsghdr.Type == unix.RTM_GETROUTE && route.LinkIndex > 0) { 1183 b := make([]byte, 4) 1184 native.PutUint32(b, uint32(route.LinkIndex)) 1185 req.AddData(nl.NewRtAttr(unix.RTA_OIF, b)) 1186 } 1187 return nil 1188 } 1189 1190 // RouteList gets a list of routes in the system. 1191 // Equivalent to: `ip route show`. 1192 // The list can be filtered by link and ip family. 1193 // 1194 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 1195 // or incomplete. 1196 func RouteList(link Link, family int) ([]Route, error) { 1197 return pkgHandle.RouteList(link, family) 1198 } 1199 1200 // RouteList gets a list of routes in the system. 1201 // Equivalent to: `ip route show`. 1202 // The list can be filtered by link and ip family. 1203 // 1204 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 1205 // or incomplete. 1206 func (h *Handle) RouteList(link Link, family int) ([]Route, error) { 1207 routeFilter := &Route{} 1208 if link != nil { 1209 routeFilter.LinkIndex = link.Attrs().Index 1210 1211 return h.RouteListFiltered(family, routeFilter, RT_FILTER_OIF) 1212 } 1213 return h.RouteListFiltered(family, routeFilter, 0) 1214 } 1215 1216 // RouteListFiltered gets a list of routes in the system filtered with specified rules. 1217 // All rules must be defined in RouteFilter struct 1218 func RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) { 1219 return pkgHandle.RouteListFiltered(family, filter, filterMask) 1220 } 1221 1222 // RouteListFiltered gets a list of routes in the system filtered with specified rules. 1223 // All rules must be defined in RouteFilter struct 1224 // 1225 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 1226 // or incomplete. 1227 func (h *Handle) RouteListFiltered(family int, filter *Route, filterMask uint64) ([]Route, error) { 1228 var res []Route 1229 err := h.RouteListFilteredIter(family, filter, filterMask, func(route Route) (cont bool) { 1230 res = append(res, route) 1231 return true 1232 }) 1233 if err != nil { 1234 return nil, err 1235 } 1236 return res, nil 1237 } 1238 1239 // RouteListFilteredIter passes each route that matches the filter to the given iterator func. Iteration continues 1240 // until all routes are loaded or the func returns false. 1241 // 1242 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 1243 // or incomplete. 1244 func RouteListFilteredIter(family int, filter *Route, filterMask uint64, f func(Route) (cont bool)) error { 1245 return pkgHandle.RouteListFilteredIter(family, filter, filterMask, f) 1246 } 1247 1248 // If the returned error is [ErrDumpInterrupted], results may be inconsistent 1249 // or incomplete. 1250 func (h *Handle) RouteListFilteredIter(family int, filter *Route, filterMask uint64, f func(Route) (cont bool)) error { 1251 req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_DUMP) 1252 rtmsg := &nl.RtMsg{} 1253 rtmsg.Family = uint8(family) 1254 1255 var parseErr error 1256 executeErr := h.routeHandleIter(filter, req, rtmsg, func(m []byte) bool { 1257 msg := nl.DeserializeRtMsg(m) 1258 if family != FAMILY_ALL && msg.Family != uint8(family) { 1259 // Ignore routes not matching requested family 1260 return true 1261 } 1262 if msg.Flags&unix.RTM_F_CLONED != 0 { 1263 // Ignore cloned routes 1264 return true 1265 } 1266 if msg.Table != unix.RT_TABLE_MAIN { 1267 if filter == nil || filterMask&RT_FILTER_TABLE == 0 { 1268 // Ignore non-main tables 1269 return true 1270 } 1271 } 1272 route, err := deserializeRoute(m) 1273 if err != nil { 1274 parseErr = err 1275 return false 1276 } 1277 if filter != nil { 1278 switch { 1279 case filterMask&RT_FILTER_TABLE != 0 && filter.Table != unix.RT_TABLE_UNSPEC && route.Table != filter.Table: 1280 return true 1281 case filterMask&RT_FILTER_PROTOCOL != 0 && route.Protocol != filter.Protocol: 1282 return true 1283 case filterMask&RT_FILTER_SCOPE != 0 && route.Scope != filter.Scope: 1284 return true 1285 case filterMask&RT_FILTER_TYPE != 0 && route.Type != filter.Type: 1286 return true 1287 case filterMask&RT_FILTER_TOS != 0 && route.Tos != filter.Tos: 1288 return true 1289 case filterMask&RT_FILTER_REALM != 0 && route.Realm != filter.Realm: 1290 return true 1291 case filterMask&RT_FILTER_OIF != 0 && route.LinkIndex != filter.LinkIndex: 1292 return true 1293 case filterMask&RT_FILTER_IIF != 0 && route.ILinkIndex != filter.ILinkIndex: 1294 return true 1295 case filterMask&RT_FILTER_GW != 0 && !route.Gw.Equal(filter.Gw): 1296 return true 1297 case filterMask&RT_FILTER_SRC != 0 && !route.Src.Equal(filter.Src): 1298 return true 1299 case filterMask&RT_FILTER_DST != 0: 1300 if filter.MPLSDst == nil || route.MPLSDst == nil || (*filter.MPLSDst) != (*route.MPLSDst) { 1301 if filter.Dst == nil { 1302 filter.Dst = genZeroIPNet(family) 1303 } 1304 if !ipNetEqual(route.Dst, filter.Dst) { 1305 return true 1306 } 1307 } 1308 case filterMask&RT_FILTER_HOPLIMIT != 0 && route.Hoplimit != filter.Hoplimit: 1309 return true 1310 } 1311 } 1312 return f(route) 1313 }) 1314 if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) { 1315 return executeErr 1316 } 1317 if parseErr != nil { 1318 return parseErr 1319 } 1320 return executeErr 1321 } 1322 1323 // deserializeRoute decodes a binary netlink message into a Route struct 1324 func deserializeRoute(m []byte) (Route, error) { 1325 msg := nl.DeserializeRtMsg(m) 1326 attrs, err := nl.ParseRouteAttr(m[msg.Len():]) 1327 if err != nil { 1328 return Route{}, err 1329 } 1330 route := Route{ 1331 Scope: Scope(msg.Scope), 1332 Protocol: RouteProtocol(int(msg.Protocol)), 1333 Table: int(msg.Table), 1334 Type: int(msg.Type), 1335 Tos: int(msg.Tos), 1336 Flags: int(msg.Flags), 1337 Family: int(msg.Family), 1338 } 1339 1340 var encap, encapType syscall.NetlinkRouteAttr 1341 for _, attr := range attrs { 1342 switch attr.Attr.Type { 1343 case unix.RTA_GATEWAY: 1344 route.Gw = net.IP(attr.Value) 1345 case unix.RTA_PREFSRC: 1346 route.Src = net.IP(attr.Value) 1347 case unix.RTA_DST: 1348 if msg.Family == nl.FAMILY_MPLS { 1349 stack := nl.DecodeMPLSStack(attr.Value) 1350 if len(stack) == 0 || len(stack) > 1 { 1351 return route, fmt.Errorf("invalid MPLS RTA_DST") 1352 } 1353 route.MPLSDst = &stack[0] 1354 } else { 1355 route.Dst = &net.IPNet{ 1356 IP: attr.Value, 1357 Mask: net.CIDRMask(int(msg.Dst_len), 8*len(attr.Value)), 1358 } 1359 } 1360 case unix.RTA_OIF: 1361 route.LinkIndex = int(native.Uint32(attr.Value[0:4])) 1362 case unix.RTA_IIF: 1363 route.ILinkIndex = int(native.Uint32(attr.Value[0:4])) 1364 case unix.RTA_PRIORITY: 1365 route.Priority = int(native.Uint32(attr.Value[0:4])) 1366 case unix.RTA_FLOW: 1367 route.Realm = int(native.Uint32(attr.Value[0:4])) 1368 case unix.RTA_TABLE: 1369 route.Table = int(native.Uint32(attr.Value[0:4])) 1370 case unix.RTA_MULTIPATH: 1371 parseRtNexthop := func(value []byte) (*NexthopInfo, []byte, error) { 1372 if len(value) < unix.SizeofRtNexthop { 1373 return nil, nil, fmt.Errorf("lack of bytes") 1374 } 1375 nh := nl.DeserializeRtNexthop(value) 1376 if len(value) < int(nh.RtNexthop.Len) { 1377 return nil, nil, fmt.Errorf("lack of bytes") 1378 } 1379 info := &NexthopInfo{ 1380 LinkIndex: int(nh.RtNexthop.Ifindex), 1381 Hops: int(nh.RtNexthop.Hops), 1382 Flags: int(nh.RtNexthop.Flags), 1383 } 1384 attrs, err := nl.ParseRouteAttr(value[unix.SizeofRtNexthop:int(nh.RtNexthop.Len)]) 1385 if err != nil { 1386 return nil, nil, err 1387 } 1388 var encap, encapType syscall.NetlinkRouteAttr 1389 for _, attr := range attrs { 1390 switch attr.Attr.Type { 1391 case unix.RTA_GATEWAY: 1392 info.Gw = net.IP(attr.Value) 1393 case unix.RTA_NEWDST: 1394 var d Destination 1395 switch msg.Family { 1396 case nl.FAMILY_MPLS: 1397 d = &MPLSDestination{} 1398 } 1399 if err := d.Decode(attr.Value); err != nil { 1400 return nil, nil, err 1401 } 1402 info.NewDst = d 1403 case unix.RTA_ENCAP_TYPE: 1404 encapType = attr 1405 case unix.RTA_ENCAP: 1406 encap = attr 1407 case unix.RTA_VIA: 1408 d := &Via{} 1409 if err := d.Decode(attr.Value); err != nil { 1410 return nil, nil, err 1411 } 1412 info.Via = d 1413 } 1414 } 1415 1416 if len(encap.Value) != 0 && len(encapType.Value) != 0 { 1417 typ := int(native.Uint16(encapType.Value[0:2])) 1418 var e Encap 1419 switch typ { 1420 case nl.LWTUNNEL_ENCAP_MPLS: 1421 e = &MPLSEncap{} 1422 if err := e.Decode(encap.Value); err != nil { 1423 return nil, nil, err 1424 } 1425 } 1426 info.Encap = e 1427 } 1428 1429 return info, value[int(nh.RtNexthop.Len):], nil 1430 } 1431 rest := attr.Value 1432 for len(rest) > 0 { 1433 info, buf, err := parseRtNexthop(rest) 1434 if err != nil { 1435 return route, err 1436 } 1437 route.MultiPath = append(route.MultiPath, info) 1438 rest = buf 1439 } 1440 case unix.RTA_NEWDST: 1441 var d Destination 1442 switch msg.Family { 1443 case nl.FAMILY_MPLS: 1444 d = &MPLSDestination{} 1445 } 1446 if err := d.Decode(attr.Value); err != nil { 1447 return route, err 1448 } 1449 route.NewDst = d 1450 case unix.RTA_VIA: 1451 v := &Via{} 1452 if err := v.Decode(attr.Value); err != nil { 1453 return route, err 1454 } 1455 route.Via = v 1456 case unix.RTA_ENCAP_TYPE: 1457 encapType = attr 1458 case unix.RTA_ENCAP: 1459 encap = attr 1460 case unix.RTA_METRICS: 1461 metrics, err := nl.ParseRouteAttr(attr.Value) 1462 if err != nil { 1463 return route, err 1464 } 1465 for _, metric := range metrics { 1466 switch metric.Attr.Type { 1467 case unix.RTAX_MTU: 1468 route.MTU = int(native.Uint32(metric.Value[0:4])) 1469 case unix.RTAX_LOCK: 1470 route.MTULock = native.Uint32(metric.Value[0:4]) == uint32(1<<unix.RTAX_MTU) 1471 route.RtoMinLock = native.Uint32(metric.Value[0:4]) == uint32(1<<unix.RTAX_RTO_MIN) 1472 case unix.RTAX_WINDOW: 1473 route.Window = int(native.Uint32(metric.Value[0:4])) 1474 case unix.RTAX_RTT: 1475 route.Rtt = int(native.Uint32(metric.Value[0:4])) 1476 case unix.RTAX_RTTVAR: 1477 route.RttVar = int(native.Uint32(metric.Value[0:4])) 1478 case unix.RTAX_SSTHRESH: 1479 route.Ssthresh = int(native.Uint32(metric.Value[0:4])) 1480 case unix.RTAX_CWND: 1481 route.Cwnd = int(native.Uint32(metric.Value[0:4])) 1482 case unix.RTAX_ADVMSS: 1483 route.AdvMSS = int(native.Uint32(metric.Value[0:4])) 1484 case unix.RTAX_REORDERING: 1485 route.Reordering = int(native.Uint32(metric.Value[0:4])) 1486 case unix.RTAX_HOPLIMIT: 1487 route.Hoplimit = int(native.Uint32(metric.Value[0:4])) 1488 case unix.RTAX_INITCWND: 1489 route.InitCwnd = int(native.Uint32(metric.Value[0:4])) 1490 case unix.RTAX_FEATURES: 1491 route.Features = int(native.Uint32(metric.Value[0:4])) 1492 case unix.RTAX_RTO_MIN: 1493 route.RtoMin = int(native.Uint32(metric.Value[0:4])) 1494 case unix.RTAX_INITRWND: 1495 route.InitRwnd = int(native.Uint32(metric.Value[0:4])) 1496 case unix.RTAX_QUICKACK: 1497 route.QuickACK = int(native.Uint32(metric.Value[0:4])) 1498 case unix.RTAX_CC_ALGO: 1499 route.Congctl = nl.BytesToString(metric.Value) 1500 case unix.RTAX_FASTOPEN_NO_COOKIE: 1501 route.FastOpenNoCookie = int(native.Uint32(metric.Value[0:4])) 1502 } 1503 } 1504 } 1505 } 1506 1507 // Same logic to generate "default" dst with iproute2 implementation 1508 if route.Dst == nil { 1509 var addLen int 1510 var ip net.IP 1511 switch msg.Family { 1512 case FAMILY_V4: 1513 addLen = net.IPv4len 1514 ip = net.IPv4zero 1515 case FAMILY_V6: 1516 addLen = net.IPv6len 1517 ip = net.IPv6zero 1518 } 1519 1520 if addLen != 0 { 1521 route.Dst = &net.IPNet{ 1522 IP: ip, 1523 Mask: net.CIDRMask(int(msg.Dst_len), 8*addLen), 1524 } 1525 } 1526 } 1527 1528 if len(encap.Value) != 0 && len(encapType.Value) != 0 { 1529 typ := int(native.Uint16(encapType.Value[0:2])) 1530 var e Encap 1531 switch typ { 1532 case nl.LWTUNNEL_ENCAP_MPLS: 1533 e = &MPLSEncap{} 1534 if err := e.Decode(encap.Value); err != nil { 1535 return route, err 1536 } 1537 case nl.LWTUNNEL_ENCAP_SEG6: 1538 e = &SEG6Encap{} 1539 if err := e.Decode(encap.Value); err != nil { 1540 return route, err 1541 } 1542 case nl.LWTUNNEL_ENCAP_SEG6_LOCAL: 1543 e = &SEG6LocalEncap{} 1544 if err := e.Decode(encap.Value); err != nil { 1545 return route, err 1546 } 1547 case nl.LWTUNNEL_ENCAP_BPF: 1548 e = &BpfEncap{} 1549 if err := e.Decode(encap.Value); err != nil { 1550 return route, err 1551 } 1552 } 1553 route.Encap = e 1554 } 1555 1556 return route, nil 1557 } 1558 1559 // RouteGetOptions contains a set of options to use with 1560 // RouteGetWithOptions 1561 type RouteGetOptions struct { 1562 Iif string 1563 IifIndex int 1564 Oif string 1565 OifIndex int 1566 VrfName string 1567 SrcAddr net.IP 1568 UID *uint32 1569 Mark uint32 1570 FIBMatch bool 1571 } 1572 1573 // RouteGetWithOptions gets a route to a specific destination from the host system. 1574 // Equivalent to: 'ip route get <> vrf <VrfName>'. 1575 func RouteGetWithOptions(destination net.IP, options *RouteGetOptions) ([]Route, error) { 1576 return pkgHandle.RouteGetWithOptions(destination, options) 1577 } 1578 1579 // RouteGet gets a route to a specific destination from the host system. 1580 // Equivalent to: 'ip route get'. 1581 func RouteGet(destination net.IP) ([]Route, error) { 1582 return pkgHandle.RouteGet(destination) 1583 } 1584 1585 // RouteGetWithOptions gets a route to a specific destination from the host system. 1586 // Equivalent to: 'ip route get <> vrf <VrfName>'. 1587 func (h *Handle) RouteGetWithOptions(destination net.IP, options *RouteGetOptions) ([]Route, error) { 1588 req := h.newNetlinkRequest(unix.RTM_GETROUTE, unix.NLM_F_REQUEST) 1589 family := nl.GetIPFamily(destination) 1590 var destinationData []byte 1591 var bitlen uint8 1592 if family == FAMILY_V4 { 1593 destinationData = destination.To4() 1594 bitlen = 32 1595 } else { 1596 destinationData = destination.To16() 1597 bitlen = 128 1598 } 1599 msg := &nl.RtMsg{} 1600 msg.Family = uint8(family) 1601 msg.Dst_len = bitlen 1602 if options != nil && options.SrcAddr != nil { 1603 msg.Src_len = bitlen 1604 } 1605 msg.Flags = unix.RTM_F_LOOKUP_TABLE 1606 if options != nil && options.FIBMatch { 1607 msg.Flags |= unix.RTM_F_FIB_MATCH 1608 } 1609 req.AddData(msg) 1610 1611 rtaDst := nl.NewRtAttr(unix.RTA_DST, destinationData) 1612 req.AddData(rtaDst) 1613 1614 if options != nil { 1615 if options.VrfName != "" { 1616 link, err := h.LinkByName(options.VrfName) 1617 if err != nil { 1618 return nil, err 1619 } 1620 b := make([]byte, 4) 1621 native.PutUint32(b, uint32(link.Attrs().Index)) 1622 1623 req.AddData(nl.NewRtAttr(unix.RTA_OIF, b)) 1624 } 1625 1626 iifIndex := 0 1627 if len(options.Iif) > 0 { 1628 link, err := h.LinkByName(options.Iif) 1629 if err != nil { 1630 return nil, err 1631 } 1632 1633 iifIndex = link.Attrs().Index 1634 } else if options.IifIndex > 0 { 1635 iifIndex = options.IifIndex 1636 } 1637 1638 if iifIndex > 0 { 1639 b := make([]byte, 4) 1640 native.PutUint32(b, uint32(iifIndex)) 1641 1642 req.AddData(nl.NewRtAttr(unix.RTA_IIF, b)) 1643 } 1644 1645 oifIndex := uint32(0) 1646 if len(options.Oif) > 0 { 1647 link, err := h.LinkByName(options.Oif) 1648 if err != nil { 1649 return nil, err 1650 } 1651 oifIndex = uint32(link.Attrs().Index) 1652 } else if options.OifIndex > 0 { 1653 oifIndex = uint32(options.OifIndex) 1654 } 1655 1656 if oifIndex > 0 { 1657 b := make([]byte, 4) 1658 native.PutUint32(b, oifIndex) 1659 1660 req.AddData(nl.NewRtAttr(unix.RTA_OIF, b)) 1661 } 1662 1663 if options.SrcAddr != nil { 1664 var srcAddr []byte 1665 if family == FAMILY_V4 { 1666 srcAddr = options.SrcAddr.To4() 1667 } else { 1668 srcAddr = options.SrcAddr.To16() 1669 } 1670 1671 req.AddData(nl.NewRtAttr(unix.RTA_SRC, srcAddr)) 1672 } 1673 1674 if options.UID != nil { 1675 uid := *options.UID 1676 b := make([]byte, 4) 1677 native.PutUint32(b, uid) 1678 1679 req.AddData(nl.NewRtAttr(unix.RTA_UID, b)) 1680 } 1681 1682 if options.Mark > 0 { 1683 b := make([]byte, 4) 1684 native.PutUint32(b, options.Mark) 1685 1686 req.AddData(nl.NewRtAttr(unix.RTA_MARK, b)) 1687 } 1688 } 1689 1690 msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWROUTE) 1691 if err != nil { 1692 return nil, err 1693 } 1694 1695 var res []Route 1696 for _, m := range msgs { 1697 route, err := deserializeRoute(m) 1698 if err != nil { 1699 return nil, err 1700 } 1701 res = append(res, route) 1702 } 1703 return res, nil 1704 } 1705 1706 // RouteGet gets a route to a specific destination from the host system. 1707 // Equivalent to: 'ip route get'. 1708 func (h *Handle) RouteGet(destination net.IP) ([]Route, error) { 1709 return h.RouteGetWithOptions(destination, nil) 1710 } 1711 1712 // RouteSubscribe takes a chan down which notifications will be sent 1713 // when routes are added or deleted. Close the 'done' chan to stop subscription. 1714 func RouteSubscribe(ch chan<- RouteUpdate, done <-chan struct{}) error { 1715 return routeSubscribeAt(netns.None(), netns.None(), ch, done, nil, false, 0, nil, false) 1716 } 1717 1718 // RouteSubscribeAt works like RouteSubscribe plus it allows the caller 1719 // to choose the network namespace in which to subscribe (ns). 1720 func RouteSubscribeAt(ns netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}) error { 1721 return routeSubscribeAt(ns, netns.None(), ch, done, nil, false, 0, nil, false) 1722 } 1723 1724 // RouteSubscribeOptions contains a set of options to use with 1725 // RouteSubscribeWithOptions. 1726 type RouteSubscribeOptions struct { 1727 Namespace *netns.NsHandle 1728 ErrorCallback func(error) 1729 ListExisting bool 1730 ReceiveBufferSize int 1731 ReceiveBufferForceSize bool 1732 ReceiveTimeout *unix.Timeval 1733 } 1734 1735 // RouteSubscribeWithOptions work like RouteSubscribe but enable to 1736 // provide additional options to modify the behavior. Currently, the 1737 // namespace can be provided as well as an error callback. 1738 // 1739 // When options.ListExisting is true, options.ErrorCallback may be 1740 // called with [ErrDumpInterrupted] to indicate that results from 1741 // the initial dump of links may be inconsistent or incomplete. 1742 func RouteSubscribeWithOptions(ch chan<- RouteUpdate, done <-chan struct{}, options RouteSubscribeOptions) error { 1743 if options.Namespace == nil { 1744 none := netns.None() 1745 options.Namespace = &none 1746 } 1747 return routeSubscribeAt(*options.Namespace, netns.None(), ch, done, options.ErrorCallback, options.ListExisting, 1748 options.ReceiveBufferSize, options.ReceiveTimeout, options.ReceiveBufferForceSize) 1749 } 1750 1751 func routeSubscribeAt(newNs, curNs netns.NsHandle, ch chan<- RouteUpdate, done <-chan struct{}, cberr func(error), listExisting bool, 1752 rcvbuf int, rcvTimeout *unix.Timeval, rcvbufForce bool) error { 1753 s, err := nl.SubscribeAt(newNs, curNs, unix.NETLINK_ROUTE, unix.RTNLGRP_IPV4_ROUTE, unix.RTNLGRP_IPV6_ROUTE) 1754 if err != nil { 1755 return err 1756 } 1757 if rcvTimeout != nil { 1758 if err := s.SetReceiveTimeout(rcvTimeout); err != nil { 1759 return err 1760 } 1761 } 1762 if rcvbuf != 0 { 1763 err = s.SetReceiveBufferSize(rcvbuf, rcvbufForce) 1764 if err != nil { 1765 return err 1766 } 1767 } 1768 if done != nil { 1769 go func() { 1770 <-done 1771 s.Close() 1772 }() 1773 } 1774 if listExisting { 1775 req := pkgHandle.newNetlinkRequest(unix.RTM_GETROUTE, 1776 unix.NLM_F_DUMP) 1777 infmsg := nl.NewIfInfomsg(unix.AF_UNSPEC) 1778 req.AddData(infmsg) 1779 if err := s.Send(req); err != nil { 1780 return err 1781 } 1782 } 1783 go func() { 1784 defer close(ch) 1785 for { 1786 msgs, from, err := s.Receive() 1787 if err != nil { 1788 if cberr != nil { 1789 cberr(fmt.Errorf("Receive failed: %v", 1790 err)) 1791 } 1792 return 1793 } 1794 if from.Pid != nl.PidKernel { 1795 if cberr != nil { 1796 cberr(fmt.Errorf("Wrong sender portid %d, expected %d", from.Pid, nl.PidKernel)) 1797 } 1798 continue 1799 } 1800 for _, m := range msgs { 1801 if m.Header.Flags&unix.NLM_F_DUMP_INTR != 0 && cberr != nil { 1802 cberr(ErrDumpInterrupted) 1803 } 1804 if m.Header.Type == unix.NLMSG_DONE { 1805 continue 1806 } 1807 if m.Header.Type == unix.NLMSG_ERROR { 1808 error := int32(native.Uint32(m.Data[0:4])) 1809 if error == 0 { 1810 continue 1811 } 1812 if cberr != nil { 1813 cberr(fmt.Errorf("error message: %v", 1814 syscall.Errno(-error))) 1815 } 1816 continue 1817 } 1818 route, err := deserializeRoute(m.Data) 1819 if err != nil { 1820 if cberr != nil { 1821 cberr(err) 1822 } 1823 continue 1824 } 1825 ch <- RouteUpdate{ 1826 Type: m.Header.Type, 1827 NlFlags: m.Header.Flags & (unix.NLM_F_REPLACE | unix.NLM_F_EXCL | unix.NLM_F_CREATE | unix.NLM_F_APPEND), 1828 Route: route, 1829 } 1830 } 1831 } 1832 }() 1833 1834 return nil 1835 } 1836 1837 func (p RouteProtocol) String() string { 1838 switch int(p) { 1839 case unix.RTPROT_BABEL: 1840 return "babel" 1841 case unix.RTPROT_BGP: 1842 return "bgp" 1843 case unix.RTPROT_BIRD: 1844 return "bird" 1845 case unix.RTPROT_BOOT: 1846 return "boot" 1847 case unix.RTPROT_DHCP: 1848 return "dhcp" 1849 case unix.RTPROT_DNROUTED: 1850 return "dnrouted" 1851 case unix.RTPROT_EIGRP: 1852 return "eigrp" 1853 case unix.RTPROT_GATED: 1854 return "gated" 1855 case unix.RTPROT_ISIS: 1856 return "isis" 1857 // case unix.RTPROT_KEEPALIVED: 1858 // return "keepalived" 1859 case unix.RTPROT_KERNEL: 1860 return "kernel" 1861 case unix.RTPROT_MROUTED: 1862 return "mrouted" 1863 case unix.RTPROT_MRT: 1864 return "mrt" 1865 case unix.RTPROT_NTK: 1866 return "ntk" 1867 case unix.RTPROT_OSPF: 1868 return "ospf" 1869 case unix.RTPROT_RA: 1870 return "ra" 1871 case unix.RTPROT_REDIRECT: 1872 return "redirect" 1873 case unix.RTPROT_RIP: 1874 return "rip" 1875 case unix.RTPROT_STATIC: 1876 return "static" 1877 case unix.RTPROT_UNSPEC: 1878 return "unspec" 1879 case unix.RTPROT_XORP: 1880 return "xorp" 1881 case unix.RTPROT_ZEBRA: 1882 return "zebra" 1883 default: 1884 return strconv.Itoa(int(p)) 1885 } 1886 } 1887 1888 // genZeroIPNet returns 0.0.0.0/0 or ::/0 for IPv4 or IPv6, otherwise nil 1889 func genZeroIPNet(family int) *net.IPNet { 1890 var addLen int 1891 var ip net.IP 1892 switch family { 1893 case FAMILY_V4: 1894 addLen = net.IPv4len 1895 ip = net.IPv4zero 1896 case FAMILY_V6: 1897 addLen = net.IPv6len 1898 ip = net.IPv6zero 1899 } 1900 if addLen != 0 { 1901 return &net.IPNet{ 1902 IP: ip, 1903 Mask: net.CIDRMask(0, 8*addLen), 1904 } 1905 } 1906 return nil 1907 }