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 extractLocalPref(args []string) ([]string, bgp.PathAttributeInterface, error) { for idx, arg := range args { if arg == "local-pref" && 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.NewPathAttributeLocalPref(uint32(metric)), nil } } return args, nil, nil }
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 (path *Path) UpdatePathAttrs(global *config.Global, peer *config.Neighbor) { if peer.RouteServer.Config.RouteServerClient { return } localAddress := net.ParseIP(peer.Transport.State.LocalAddress) isZero := func(ip net.IP) bool { return ip.Equal(net.ParseIP("0.0.0.0")) || ip.Equal(net.ParseIP("::")) } nexthop := path.GetNexthop() if peer.Config.PeerType == config.PEER_TYPE_EXTERNAL { // NEXTHOP handling if !path.IsLocal() || isZero(nexthop) { path.SetNexthop(localAddress) } // AS_PATH handling path.PrependAsn(peer.Config.LocalAs, 1) // MED Handling if med := path.getPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC); med != nil && !path.IsLocal() { path.delPathAttr(bgp.BGP_ATTR_TYPE_MULTI_EXIT_DISC) } // remove local-pref attribute if pref := path.getPathAttr(bgp.BGP_ATTR_TYPE_LOCAL_PREF); pref != nil && !config.IsConfederationMember(global, peer) { path.delPathAttr(bgp.BGP_ATTR_TYPE_LOCAL_PREF) } } else if peer.Config.PeerType == config.PEER_TYPE_INTERNAL { // NEXTHOP handling for iBGP // if the path generated locally set local address as nexthop. // if not, don't modify it. // TODO: NEXT-HOP-SELF support if path.IsLocal() && isZero(nexthop) { path.SetNexthop(localAddress) } // AS_PATH handling for iBGP // if the path has AS_PATH path attribute, don't modify it. // if not, attach *empty* AS_PATH path attribute. if nh := path.getPathAttr(bgp.BGP_ATTR_TYPE_AS_PATH); nh == nil { path.PrependAsn(0, 0) } // For iBGP peers we are required to send local-pref attribute // for connected or local prefixes. // We set default local-pref 100. if pref := path.getPathAttr(bgp.BGP_ATTR_TYPE_LOCAL_PREF); pref == nil || !path.IsLocal() { path.setPathAttr(bgp.NewPathAttributeLocalPref(100)) } // RFC4456: BGP Route Reflection // 8. Avoiding Routing Information Loops info := path.GetSource() if peer.RouteReflector.Config.RouteReflectorClient { // This attribute will carry the BGP Identifier of the originator of the route in the local AS. // A BGP speaker SHOULD NOT create an ORIGINATOR_ID attribute if one already exists. if path.getPathAttr(bgp.BGP_ATTR_TYPE_ORIGINATOR_ID) == nil { path.setPathAttr(bgp.NewPathAttributeOriginatorId(info.ID.String())) } // When an RR reflects a route, it MUST prepend the local CLUSTER_ID to the CLUSTER_LIST. // If the CLUSTER_LIST is empty, it MUST create a new one. id := string(peer.RouteReflector.Config.RouteReflectorClusterId) if p := path.getPathAttr(bgp.BGP_ATTR_TYPE_CLUSTER_LIST); p == nil { path.setPathAttr(bgp.NewPathAttributeClusterList([]string{id})) } else { clusterList := p.(*bgp.PathAttributeClusterList) newClusterList := make([]string, 0, len(clusterList.Value)) for _, ip := range clusterList.Value { newClusterList = append(newClusterList, ip.String()) } path.setPathAttr(bgp.NewPathAttributeClusterList(append([]string{id}, newClusterList...))) } } } else { log.WithFields(log.Fields{ "Topic": "Peer", "Key": peer.Config.NeighborAddress, }).Warnf("invalid peer type: %d", peer.Config.PeerType) } }