// SetMed replace, add or subtraction med with new ones. func (path *Path) SetMed(med int64, doReplace bool) error { parseMed := func(orgMed uint32, med int64, doReplace bool) (*bgp.PathAttributeMultiExitDisc, error) { newMed := &bgp.PathAttributeMultiExitDisc{} if doReplace { newMed = bgp.NewPathAttributeMultiExitDisc(uint32(med)) } else { if int64(orgMed)+med < 0 { return nil, fmt.Errorf("med value invalid. it's underflow threshold.") } else if int64(orgMed)+med > int64(math.MaxUint32) { return nil, fmt.Errorf("med value invalid. it's overflow threshold.") } newMed = bgp.NewPathAttributeMultiExitDisc(uint32(int64(orgMed) + med)) } return newMed, nil } m := uint32(0) if attr := path.getPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC); attr != nil { m = attr.(*bgp.PathAttributeMultiExitDisc).Value } newMed, err := parseMed(m, med, doReplace) if err != nil { return err } path.setPathAttr(newMed) return nil }
func TestTimeTieBreaker(t *testing.T) { origin := bgp.NewPathAttributeOrigin(0) aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001})} aspath := bgp.NewPathAttributeAsPath(aspathParam) nexthop := bgp.NewPathAttributeNextHop("10.0.0.1") med := bgp.NewPathAttributeMultiExitDisc(0) pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med} nlri := bgp.NewIPAddrPrefix(24, "10.10.0.0") updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri}) peer1 := &PeerInfo{AS: 2, LocalAS: 1, Address: net.IP{1, 1, 1, 1}, ID: net.IP{1, 1, 1, 1}} path1 := ProcessMessage(updateMsg, peer1, time.Now())[0] peer2 := &PeerInfo{AS: 2, LocalAS: 1, Address: net.IP{2, 2, 2, 2}, ID: net.IP{2, 2, 2, 2}} // weaker router-id path2 := ProcessMessage(updateMsg, peer2, time.Now().Add(-1*time.Hour))[0] // older than path1 d := NewDestination(nlri) d.AddNewPath(path1) d.AddNewPath(path2) d.Calculate(nil) assert.Equal(t, len(d.knownPathList), 2) assert.Equal(t, true, d.GetBestPath("").GetSource().ID.Equal(net.IP{2, 2, 2, 2})) // path from peer2 win // this option disables tie breaking by age SelectionOptions.ExternalCompareRouterId = true d = NewDestination(nlri) d.AddNewPath(path1) d.AddNewPath(path2) d.Calculate(nil) assert.Equal(t, len(d.knownPathList), 2) assert.Equal(t, true, d.GetBestPath("").GetSource().ID.Equal(net.IP{1, 1, 1, 1})) // path from peer1 win }
func TestMrtRib(t *testing.T) { aspath1 := []bgp.AsPathParamInterface{ bgp.NewAsPathParam(2, []uint16{1000}), bgp.NewAsPathParam(1, []uint16{1001, 1002}), bgp.NewAsPathParam(2, []uint16{1003, 1004}), } p := []bgp.PathAttributeInterface{ bgp.NewPathAttributeOrigin(3), bgp.NewPathAttributeAsPath(aspath1), bgp.NewPathAttributeNextHop("129.1.1.2"), bgp.NewPathAttributeMultiExitDisc(1 << 20), bgp.NewPathAttributeLocalPref(1 << 22), } e1 := NewRibEntry(1, uint32(time.Now().Unix()), p) e2 := NewRibEntry(2, uint32(time.Now().Unix()), p) e3 := NewRibEntry(3, uint32(time.Now().Unix()), p) r1 := NewRib(1, bgp.NewIPAddrPrefix(24, "192.168.0.0"), []*RibEntry{e1, e2, e3}) b1, err := r1.Serialize() if err != nil { t.Fatal(err) } r2 := &Rib{ RouteFamily: bgp.RF_IPv4_UC, } err = r2.DecodeFromBytes(b1) if err != nil { t.Fatal(err) } assert.Equal(t, reflect.DeepEqual(r1, r2), true) }
func TestMrtRibEntry(t *testing.T) { aspath1 := []bgp.AsPathParamInterface{ bgp.NewAsPathParam(2, []uint16{1000}), bgp.NewAsPathParam(1, []uint16{1001, 1002}), bgp.NewAsPathParam(2, []uint16{1003, 1004}), } p := []bgp.PathAttributeInterface{ bgp.NewPathAttributeOrigin(3), bgp.NewPathAttributeAsPath(aspath1), bgp.NewPathAttributeNextHop("129.1.1.2"), bgp.NewPathAttributeMultiExitDisc(1 << 20), bgp.NewPathAttributeLocalPref(1 << 22), } e1 := NewRibEntry(1, uint32(time.Now().Unix()), p) b1, err := e1.Serialize() if err != nil { t.Fatal(err) } e2 := &RibEntry{} rest, err := e2.DecodeFromBytes(b1) if err != nil { t.Fatal(err) } assert.Equal(t, len(rest), 0) assert.Equal(t, reflect.DeepEqual(e1, e2), true) }
func TestASPathLen(t *testing.T) { assert := assert.New(t) origin := bgp.NewPathAttributeOrigin(0) aspathParam := []bgp.AsPathParamInterface{ bgp.NewAsPathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint16{65001, 65002, 65003, 65004, 65004, 65004, 65004, 65004, 65005}), bgp.NewAsPathParam(bgp.BGP_ASPATH_ATTR_TYPE_SET, []uint16{65001, 65002, 65003, 65004, 65005}), bgp.NewAsPathParam(bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ, []uint16{65100, 65101, 65102}), bgp.NewAsPathParam(bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SET, []uint16{65100, 65101})} aspath := bgp.NewPathAttributeAsPath(aspathParam) nexthop := bgp.NewPathAttributeNextHop("192.168.50.1") med := bgp.NewPathAttributeMultiExitDisc(0) pathAttributes := []bgp.PathAttributeInterface{ origin, aspath, nexthop, med, } nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.10.0")} bgpmsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) update := bgpmsg.Body.(*bgp.BGPUpdate) UpdatePathAttrs4ByteAs(update) peer := PathCreatePeer() p := NewPath(peer[0], update.NLRI[0], false, update.PathAttributes, time.Now(), false) assert.Equal(10, p.GetAsPathLen()) }
func TestImplicitWithdrawCalculate(t *testing.T) { origin := bgp.NewPathAttributeOrigin(0) aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001})} aspath := bgp.NewPathAttributeAsPath(aspathParam) nexthop := bgp.NewPathAttributeNextHop("10.0.0.1") med := bgp.NewPathAttributeMultiExitDisc(0) pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med} nlri := bgp.NewIPAddrPrefix(24, "10.10.0.101") updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri}) peer1 := &PeerInfo{AS: 1, Address: net.IP{1, 1, 1, 1}} path1 := ProcessMessage(updateMsg, peer1, time.Now())[0] path1.Filter("1", POLICY_DIRECTION_IMPORT) // suppose peer2 has import policy to prepend as-path action := &AsPathPrependAction{ asn: 100, repeat: 1, } path2 := action.Apply(path1.Clone(false), nil) path1.Filter("2", POLICY_DIRECTION_IMPORT) path2.Filter("1", POLICY_DIRECTION_IMPORT) path2.Filter("3", POLICY_DIRECTION_IMPORT) d := NewDestination(nlri) d.AddNewPath(path1) d.AddNewPath(path2) d.Calculate(nil) assert.Equal(t, len(d.GetKnownPathList("1")), 0) // peer "1" is the originator assert.Equal(t, len(d.GetKnownPathList("2")), 1) assert.Equal(t, d.GetKnownPathList("2")[0].GetAsString(), "100 65001") // peer "2" has modified path {100, 65001} assert.Equal(t, len(d.GetKnownPathList("3")), 1) assert.Equal(t, d.GetKnownPathList("3")[0].GetAsString(), "65001") // peer "3" has original path {65001} assert.Equal(t, len(d.knownPathList), 2) // say, we removed peer2's import policy and // peer1 advertised new path with the same prefix aspathParam = []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001, 65002})} aspath = bgp.NewPathAttributeAsPath(aspathParam) pathAttributes = []bgp.PathAttributeInterface{origin, aspath, nexthop, med} updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri}) path3 := ProcessMessage(updateMsg, peer1, time.Now())[0] path3.Filter("1", POLICY_DIRECTION_IMPORT) d.AddNewPath(path3) d.Calculate(nil) assert.Equal(t, len(d.GetKnownPathList("1")), 0) // peer "1" is the originator assert.Equal(t, len(d.GetKnownPathList("2")), 1) assert.Equal(t, d.GetKnownPathList("2")[0].GetAsString(), "65001 65002") // peer "2" has new original path {65001, 65002} assert.Equal(t, len(d.GetKnownPathList("3")), 1) assert.Equal(t, d.GetKnownPathList("3")[0].GetAsString(), "65001 65002") // peer "3" has new original path {65001, 65002} assert.Equal(t, len(d.knownPathList), 1) }
func TestCalculate2(t *testing.T) { origin := bgp.NewPathAttributeOrigin(0) aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001})} aspath := bgp.NewPathAttributeAsPath(aspathParam) nexthop := bgp.NewPathAttributeNextHop("10.0.0.1") med := bgp.NewPathAttributeMultiExitDisc(0) pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med} nlri := bgp.NewIPAddrPrefix(24, "10.10.0.0") // peer1 sends normal update message 10.10.0.0/24 update1 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri}) peer1 := &PeerInfo{AS: 1, Address: net.IP{1, 1, 1, 1}} path1 := ProcessMessage(update1, peer1, time.Now())[0] d := NewDestination(nlri) d.AddNewPath(path1) d.Calculate(nil) // suppose peer2 sends grammaatically correct but semantically flawed update message // which has a withdrawal nlri not advertised before update2 := bgp.NewBGPUpdateMessage([]*bgp.IPAddrPrefix{nlri}, pathAttributes, nil) peer2 := &PeerInfo{AS: 2, Address: net.IP{2, 2, 2, 2}} path2 := ProcessMessage(update2, peer2, time.Now())[0] assert.Equal(t, path2.IsWithdraw, true) d.AddWithdraw(path2) d.Calculate(nil) // we have a path from peer1 here assert.Equal(t, len(d.knownPathList), 1) // after that, new update with the same nlri comes from peer2 update3 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri}) path3 := ProcessMessage(update3, peer2, time.Now())[0] assert.Equal(t, path3.IsWithdraw, false) d.AddNewPath(path3) d.Calculate(nil) // this time, we have paths from peer1 and peer2 assert.Equal(t, len(d.knownPathList), 2) // now peer3 sends normal update message 10.10.0.0/24 peer3 := &PeerInfo{AS: 3, Address: net.IP{3, 3, 3, 3}} update4 := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri}) path4 := ProcessMessage(update4, peer3, time.Now())[0] d.AddNewPath(path4) d.Calculate(nil) // we must have paths from peer1, peer2 and peer3 assert.Equal(t, len(d.knownPathList), 3) }
func createPathFromIPRouteMessage(m *zebra.Message) *table.Path { header := m.Header body := m.Body.(*zebra.IPRouteBody) family := bgp.RF_IPv6_UC if header.Command == zebra.IPV4_ROUTE_ADD || header.Command == zebra.IPV4_ROUTE_DELETE { family = bgp.RF_IPv4_UC } var nlri bgp.AddrPrefixInterface pattr := make([]bgp.PathAttributeInterface, 0) var mpnlri *bgp.PathAttributeMpReachNLRI var isWithdraw bool = header.Command == zebra.IPV4_ROUTE_DELETE || header.Command == zebra.IPV6_ROUTE_DELETE origin := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP) pattr = append(pattr, origin) log.WithFields(log.Fields{ "Topic": "Zebra", "RouteType": body.Type.String(), "Flag": body.Flags.String(), "Message": body.Message, "Prefix": body.Prefix, "PrefixLength": body.PrefixLength, "Nexthop": body.Nexthops, "IfIndex": body.Ifindexs, "Metric": body.Metric, "Distance": body.Distance, "api": header.Command.String(), }).Debugf("create path from ip route message.") switch family { case bgp.RF_IPv4_UC: nlri = bgp.NewIPAddrPrefix(body.PrefixLength, body.Prefix.String()) nexthop := bgp.NewPathAttributeNextHop(body.Nexthops[0].String()) pattr = append(pattr, nexthop) case bgp.RF_IPv6_UC: nlri = bgp.NewIPv6AddrPrefix(body.PrefixLength, body.Prefix.String()) mpnlri = bgp.NewPathAttributeMpReachNLRI(body.Nexthops[0].String(), []bgp.AddrPrefixInterface{nlri}) pattr = append(pattr, mpnlri) default: log.WithFields(log.Fields{ "Topic": "Zebra", }).Errorf("unsupport address family: %s", family) return nil } med := bgp.NewPathAttributeMultiExitDisc(body.Metric) pattr = append(pattr, med) path := table.NewPath(nil, nlri, isWithdraw, pattr, time.Now(), false) path.SetIsFromExternal(true) return path }
func TestMedTieBreaker(t *testing.T) { nlri := bgp.NewIPAddrPrefix(24, "10.10.0.0") p0 := func() *Path { aspath := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65001, 65002}), bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65003, 65004})}) attrs := []bgp.PathAttributeInterface{aspath, bgp.NewPathAttributeMultiExitDisc(0)} return NewPath(nil, nlri, false, attrs, time.Now(), false) }() p1 := func() *Path { aspath := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65001, 65002}), bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65003, 65005})}) attrs := []bgp.PathAttributeInterface{aspath, bgp.NewPathAttributeMultiExitDisc(10)} return NewPath(nil, nlri, false, attrs, time.Now(), false) }() // same AS assert.Equal(t, compareByMED(p0, p1), p0) p2 := func() *Path { aspath := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65003})}) attrs := []bgp.PathAttributeInterface{aspath, bgp.NewPathAttributeMultiExitDisc(10)} return NewPath(nil, nlri, false, attrs, time.Now(), false) }() // different AS assert.Equal(t, compareByMED(p0, p2), (*Path)(nil)) p3 := func() *Path { aspath := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ, []uint32{65003, 65004}), bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65001, 65003})}) attrs := []bgp.PathAttributeInterface{aspath, bgp.NewPathAttributeMultiExitDisc(0)} return NewPath(nil, nlri, false, attrs, time.Now(), false) }() p4 := func() *Path { aspath := bgp.NewPathAttributeAsPath([]bgp.AsPathParamInterface{bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_SEQ, []uint32{65001, 65002}), bgp.NewAs4PathParam(bgp.BGP_ASPATH_ATTR_TYPE_CONFED_SEQ, []uint32{65005, 65006})}) attrs := []bgp.PathAttributeInterface{aspath, bgp.NewPathAttributeMultiExitDisc(10)} return NewPath(nil, nlri, false, attrs, time.Now(), false) }() // ignore confed assert.Equal(t, compareByMED(p3, p4), p3) p5 := func() *Path { attrs := []bgp.PathAttributeInterface{bgp.NewPathAttributeMultiExitDisc(0)} return NewPath(nil, nlri, false, attrs, time.Now(), false) }() p6 := func() *Path { attrs := []bgp.PathAttributeInterface{bgp.NewPathAttributeMultiExitDisc(10)} return NewPath(nil, nlri, false, attrs, time.Now(), false) }() // no aspath assert.Equal(t, compareByMED(p5, p6), p5) }
func extractMed(args []string) ([]string, bgp.PathAttributeInterface, error) { for idx, arg := range args { if arg == "med" && len(args) > (idx+1) { metric, err := strconv.Atoi(args[idx+1]) if err != nil { return nil, nil, err } args = append(args[:idx], args[idx+2:]...) return args, bgp.NewPathAttributeMultiExitDisc(uint32(metric)), nil } } return args, nil, nil }
func createPathFromIPRouteMessage(m *zebra.Message, peerInfo *table.PeerInfo) *table.Path { header := m.Header body := m.Body.(*zebra.IPRouteBody) isV4 := header.Command == zebra.IPV4_ROUTE_ADD || header.Command == zebra.IPV4_ROUTE_DELETE var nlri bgp.AddrPrefixInterface pattr := make([]bgp.PathAttributeInterface, 0) var mpnlri *bgp.PathAttributeMpReachNLRI var isWithdraw bool = header.Command == zebra.IPV4_ROUTE_DELETE || header.Command == zebra.IPV6_ROUTE_DELETE origin := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP) pattr = append(pattr, origin) log.WithFields(log.Fields{ "Topic": "Zebra", "RouteType": body.Type.String(), "Flag": body.Flags.String(), "Message": body.Message, "Prefix": body.Prefix, "PrefixLength": body.PrefixLength, "Nexthop": body.Nexthops, "IfIndex": body.Ifindexs, "Metric": body.Metric, "Distance": body.Distance, "api": header.Command.String(), }).Debugf("create path from ip route message.") if isV4 { nlri = bgp.NewIPAddrPrefix(body.PrefixLength, body.Prefix.String()) nexthop := bgp.NewPathAttributeNextHop(body.Nexthops[0].String()) pattr = append(pattr, nexthop) } else { nlri = bgp.NewIPv6AddrPrefix(body.PrefixLength, body.Prefix.String()) mpnlri = bgp.NewPathAttributeMpReachNLRI(body.Nexthops[0].String(), []bgp.AddrPrefixInterface{nlri}) pattr = append(pattr, mpnlri) } med := bgp.NewPathAttributeMultiExitDisc(body.Metric) pattr = append(pattr, med) p := table.NewPath(peerInfo, nlri, isWithdraw, pattr, time.Now(), false) p.SetIsFromExternal(true) return p }
func updateMsgP2() *bgp.BGPMessage { origin := bgp.NewPathAttributeOrigin(0) aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65100})} aspath := bgp.NewPathAttributeAsPath(aspathParam) nexthop := bgp.NewPathAttributeNextHop("192.168.100.1") med := bgp.NewPathAttributeMultiExitDisc(100) pathAttributes := []bgp.PathAttributeInterface{ origin, aspath, nexthop, med, } nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "20.20.20.0")} return bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) }
func updateMsgD1() *bgp.BGPMessage { origin := bgp.NewPathAttributeOrigin(0) aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65000})} aspath := bgp.NewPathAttributeAsPath(aspathParam) nexthop := bgp.NewPathAttributeNextHop("192.168.50.1") med := bgp.NewPathAttributeMultiExitDisc(0) pathAttributes := []bgp.PathAttributeInterface{ origin, aspath, nexthop, med, } nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.10.0")} updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate)) return updateMsg }
func updateMsgD3() *bgp.BGPMessage { origin := bgp.NewPathAttributeOrigin(0) aspathParam := []bgp.AsPathParamInterface{bgp.NewAsPathParam(2, []uint16{65100})} aspath := bgp.NewPathAttributeAsPath(aspathParam) nexthop := bgp.NewPathAttributeNextHop("192.168.150.1") med := bgp.NewPathAttributeMultiExitDisc(100) pathAttributes := []bgp.PathAttributeInterface{ origin, aspath, nexthop, med, } nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "30.30.30.0")} w1 := bgp.NewIPAddrPrefix(23, "40.40.40.0") withdrawnRoutes := []*bgp.IPAddrPrefix{w1} updateMsg := bgp.NewBGPUpdateMessage(withdrawnRoutes, pathAttributes, nlri) UpdatePathAttrs4ByteAs(updateMsg.Body.(*bgp.BGPUpdate)) return updateMsg }
func TestCalculate(t *testing.T) { origin := bgp.NewPathAttributeOrigin(0) aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65001})} aspath := bgp.NewPathAttributeAsPath(aspathParam) nexthop := bgp.NewPathAttributeNextHop("10.0.0.1") med := bgp.NewPathAttributeMultiExitDisc(0) pathAttributes := []bgp.PathAttributeInterface{origin, aspath, nexthop, med} nlri := bgp.NewIPAddrPrefix(24, "10.10.0.101") updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, []*bgp.IPAddrPrefix{nlri}) peer1 := &PeerInfo{AS: 1, Address: net.IP{1, 1, 1, 1}} path1 := ProcessMessage(updateMsg, peer1, time.Now())[0] path1.Filter("1", POLICY_DIRECTION_IMPORT) action := &AsPathPrependAction{ asn: 100, repeat: 10, } path2 := action.Apply(path1.Clone(false), nil) path1.Filter("2", POLICY_DIRECTION_IMPORT) path2.Filter("1", POLICY_DIRECTION_IMPORT) d := NewDestination(nlri) d.AddNewPath(path1) d.AddNewPath(path2) d.Calculate([]string{"1", "2"}) assert.Equal(t, len(d.GetKnownPathList("1")), 0) assert.Equal(t, len(d.GetKnownPathList("2")), 1) assert.Equal(t, len(d.knownPathList), 2) d.AddWithdraw(path1.Clone(true)) d.Calculate([]string{"1", "2"}) assert.Equal(t, len(d.GetKnownPathList("1")), 0) assert.Equal(t, len(d.GetKnownPathList("2")), 0) assert.Equal(t, len(d.knownPathList), 0) }
func parseRouteToGobgp(route ovsdb.RowUpdate, nexthops map[string]ovsdb.Row) (*api.Path, bool, bool, error) { var nlri bgp.AddrPrefixInterface path := &api.Path{ IsFromExternal: true, Pattrs: make([][]byte, 0), } isWithdraw := false isFromGobgp := false prefix := route.New.Fields["prefix"].(string) safi := route.New.Fields["sub_address_family"].(string) afi := route.New.Fields["address_family"].(string) m := route.New.Fields["metric"].(float64) attrs := route.New.Fields["path_attributes"].(ovsdb.OvsMap).GoMap if attrs["IsFromGobgp"] == "true" { isFromGobgp = true } nh := make([]interface{}, 0) nhId, ok := route.New.Fields["bgp_nexthops"].(ovsdb.UUID) if ok { for id, n := range nexthops { if id == nhId.GoUUID { nh = append(nh, n.Fields["ip_address"]) } } } nexthop := "0.0.0.0" if afi == "ipv6" { nexthop = "::" } if len(nh) == 0 { log.Debug("nexthop addres does not exist") } else if len(nh) == 1 { if net.ParseIP(nh[0].(string)) == nil { return nil, isWithdraw, isFromGobgp, fmt.Errorf("invalid nexthop address") } else { nexthop = nh[0].(string) } } else { return nil, isWithdraw, isFromGobgp, fmt.Errorf("route has multiple nexthop address") } med, _ := bgp.NewPathAttributeMultiExitDisc(uint32(m)).Serialize() path.Pattrs = append(path.Pattrs, med) lpref, err := strconv.Atoi(attrs["BGP_loc_pref"].(string)) if err != nil { return nil, isWithdraw, isFromGobgp, err } localPref, _ := bgp.NewPathAttributeLocalPref(uint32(lpref)).Serialize() path.Pattrs = append(path.Pattrs, localPref) var origin_t int switch attrs["BGP_origin"].(string) { case "i": origin_t = bgp.BGP_ORIGIN_ATTR_TYPE_IGP case "e": origin_t = bgp.BGP_ORIGIN_ATTR_TYPE_EGP case "?": origin_t = bgp.BGP_ORIGIN_ATTR_TYPE_INCOMPLETE default: return nil, isWithdraw, isFromGobgp, fmt.Errorf("invalid origin") } origin, _ := bgp.NewPathAttributeOrigin(uint8(origin_t)).Serialize() path.Pattrs = append(path.Pattrs, origin) switch afi { case "ipv4", "ipv6": ip, net, err := net.ParseCIDR(prefix) if err != nil { return nil, isWithdraw, isFromGobgp, err } ones, _ := net.Mask.Size() if afi == "ipv4" { if ip.To4() == nil { return nil, isWithdraw, isFromGobgp, fmt.Errorf("invalid ipv4 prefix") } nlri = bgp.NewIPAddrPrefix(uint8(ones), ip.String()) } else { if ip.To16() == nil { return nil, isWithdraw, isFromGobgp, fmt.Errorf("invalid ipv6 prefix") } nlri = bgp.NewIPv6AddrPrefix(uint8(ones), ip.String()) } default: return nil, isWithdraw, isFromGobgp, fmt.Errorf("unsupported address family: %s", afi) } if afi == "ipv4" && safi == "unicast" { path.Nlri, _ = nlri.Serialize() n, _ := bgp.NewPathAttributeNextHop(nexthop).Serialize() path.Pattrs = append(path.Pattrs, n) } else { mpreach, _ := bgp.NewPathAttributeMpReachNLRI(nexthop, []bgp.AddrPrefixInterface{nlri}).Serialize() path.Pattrs = append(path.Pattrs, mpreach) } if attrs["BGP_flags"].(string) == "512" { isWithdraw = true } return path, isWithdraw, isFromGobgp, nil }
func createRequestFromIPRouteMessage(m *zebra.Message) *api.AddPathRequest { header := m.Header body := m.Body.(*zebra.IPRouteBody) family := bgp.RF_IPv6_UC if header.Command == zebra.IPV4_ROUTE_ADD || header.Command == zebra.IPV4_ROUTE_DELETE { family = bgp.RF_IPv4_UC } var nlri bgp.AddrPrefixInterface pattr := make([]bgp.PathAttributeInterface, 0) var mpnlri *bgp.PathAttributeMpReachNLRI var isWithdraw bool = header.Command == zebra.IPV4_ROUTE_DELETE || header.Command == zebra.IPV6_ROUTE_DELETE origin := bgp.NewPathAttributeOrigin(bgp.BGP_ORIGIN_ATTR_TYPE_IGP) pattr = append(pattr, origin) log.WithFields(log.Fields{ "Topic": "Zebra", "RouteType": body.Type.String(), "Flag": body.Flags.String(), "Message": body.Message, "Prefix": body.Prefix, "PrefixLength": body.PrefixLength, "Nexthop": body.Nexthops, "IfIndex": body.Ifindexs, "Metric": body.Metric, "Distance": body.Distance, "api": header.Command.String(), }).Debugf("create path from ip route message.") switch family { case bgp.RF_IPv4_UC: nlri = bgp.NewIPAddrPrefix(body.PrefixLength, body.Prefix.String()) nexthop := bgp.NewPathAttributeNextHop(body.Nexthops[0].String()) pattr = append(pattr, nexthop) case bgp.RF_IPv6_UC: nlri = bgp.NewIPv6AddrPrefix(body.PrefixLength, body.Prefix.String()) mpnlri = bgp.NewPathAttributeMpReachNLRI(body.Nexthops[0].String(), []bgp.AddrPrefixInterface{nlri}) pattr = append(pattr, mpnlri) default: log.WithFields(log.Fields{ "Topic": "Zebra", }).Errorf("unsupport address family: %s", family) return nil } med := bgp.NewPathAttributeMultiExitDisc(body.Metric) pattr = append(pattr, med) binPattrs := make([][]byte, 0, len(pattr)) for _, a := range pattr { bin, _ := a.Serialize() binPattrs = append(binPattrs, bin) } binNlri, _ := nlri.Serialize() path := &api.Path{ Nlri: binNlri, Pattrs: binPattrs, IsWithdraw: isWithdraw, Family: uint32(family), IsFromExternal: true, } return &api.AddPathRequest{ Resource: api.Resource_GLOBAL, Path: path, } }
func TestMultipath(t *testing.T) { UseMultiplePaths.Enabled = true origin := bgp.NewPathAttributeOrigin(0) aspathParam := []bgp.AsPathParamInterface{bgp.NewAs4PathParam(2, []uint32{65000})} aspath := bgp.NewPathAttributeAsPath(aspathParam) nexthop := bgp.NewPathAttributeNextHop("192.168.150.1") med := bgp.NewPathAttributeMultiExitDisc(100) pathAttributes := []bgp.PathAttributeInterface{ origin, aspath, nexthop, med, } nlri := []*bgp.IPAddrPrefix{bgp.NewIPAddrPrefix(24, "10.10.10.0")} updateMsg := bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) peer1 := &PeerInfo{AS: 1, Address: net.IP{1, 1, 1, 1}, ID: net.IP{1, 1, 1, 1}} path1 := ProcessMessage(updateMsg, peer1, time.Now())[0] peer2 := &PeerInfo{AS: 2, Address: net.IP{2, 2, 2, 2}, ID: net.IP{2, 2, 2, 2}} med = bgp.NewPathAttributeMultiExitDisc(100) nexthop = bgp.NewPathAttributeNextHop("192.168.150.2") pathAttributes = []bgp.PathAttributeInterface{ origin, aspath, nexthop, med, } updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) path2 := ProcessMessage(updateMsg, peer2, time.Now())[0] d := NewDestination(nlri[0]) d.AddNewPath(path1) d.AddNewPath(path2) best, w, multi := d.Calculate([]string{GLOBAL_RIB_NAME}) assert.Equal(t, len(best), 1) assert.Equal(t, len(w), 0) assert.Equal(t, len(multi), 2) assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME)), 2) path3 := path2.Clone(true) d.AddWithdraw(path3) best, w, multi = d.Calculate([]string{GLOBAL_RIB_NAME}) assert.Equal(t, len(best), 1) assert.Equal(t, len(w), 1) assert.Equal(t, len(multi), 1) assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME)), 1) peer3 := &PeerInfo{AS: 3, Address: net.IP{3, 3, 3, 3}, ID: net.IP{3, 3, 3, 3}} med = bgp.NewPathAttributeMultiExitDisc(50) nexthop = bgp.NewPathAttributeNextHop("192.168.150.3") pathAttributes = []bgp.PathAttributeInterface{ origin, aspath, nexthop, med, } updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) path4 := ProcessMessage(updateMsg, peer3, time.Now())[0] d.AddNewPath(path4) best, w, multi = d.Calculate([]string{GLOBAL_RIB_NAME}) assert.Equal(t, len(best), 1) assert.Equal(t, len(w), 0) assert.Equal(t, len(multi), 1) assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME)), 2) nexthop = bgp.NewPathAttributeNextHop("192.168.150.2") pathAttributes = []bgp.PathAttributeInterface{ origin, aspath, nexthop, med, } updateMsg = bgp.NewBGPUpdateMessage(nil, pathAttributes, nlri) path5 := ProcessMessage(updateMsg, peer2, time.Now())[0] d.AddNewPath(path5) best, w, multi = d.Calculate([]string{GLOBAL_RIB_NAME}) assert.Equal(t, len(best), 1) assert.Equal(t, len(w), 0) assert.Equal(t, len(multi), 2) assert.Equal(t, len(d.GetKnownPathList(GLOBAL_RIB_NAME)), 3) UseMultiplePaths.Enabled = false }