Merge pull request #835 from milosgajdos83/router-strategy
Router strategy
This commit is contained in:
		| @@ -319,23 +319,13 @@ func (r *router) advertiseTable() error { | |||||||
| 	for { | 	for { | ||||||
| 		select { | 		select { | ||||||
| 		case <-ticker.C: | 		case <-ticker.C: | ||||||
| 			// list routing table routes to announce | 			// do full table flush | ||||||
| 			routes, err := r.table.List() | 			events, err := r.flushRouteEvents(Update) | ||||||
| 			if err != nil { | 			if err != nil { | ||||||
| 				return fmt.Errorf("failed listing routes: %s", err) | 				return fmt.Errorf("failed flushing routes: %s", err) | ||||||
| 			} |  | ||||||
| 			// collect all the added routes before we attempt to add default gateway |  | ||||||
| 			events := make([]*Event, len(routes)) |  | ||||||
| 			for i, route := range routes { |  | ||||||
| 				event := &Event{ |  | ||||||
| 					Type:      Update, |  | ||||||
| 					Timestamp: time.Now(), |  | ||||||
| 					Route:     route, |  | ||||||
| 				} |  | ||||||
| 				events[i] = event |  | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
| 			// advertise all routes as Update events to subscribers | 			// advertise routes to subscribers | ||||||
| 			if len(events) > 0 { | 			if len(events) > 0 { | ||||||
| 				log.Debugf("Router flushing table with %d events: %s", len(events), r.options.Id) | 				log.Debugf("Router flushing table with %d events: %s", len(events), r.options.Id) | ||||||
| 				r.advertWg.Add(1) | 				r.advertWg.Add(1) | ||||||
| @@ -692,15 +682,58 @@ func (r *router) flushRouteEvents(evType EventType) ([]*Event, error) { | |||||||
| 		return nil, fmt.Errorf("failed listing routes: %s", err) | 		return nil, fmt.Errorf("failed listing routes: %s", err) | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if r.options.Advertise == AdvertiseAll { | ||||||
|  | 		// build a list of events to advertise | ||||||
|  | 		events := make([]*Event, len(routes)) | ||||||
|  | 		for i, route := range routes { | ||||||
|  | 			event := &Event{ | ||||||
|  | 				Type:      evType, | ||||||
|  | 				Timestamp: time.Now(), | ||||||
|  | 				Route:     route, | ||||||
|  | 			} | ||||||
|  | 			events[i] = event | ||||||
|  | 		} | ||||||
|  | 		return events, nil | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	// routeMap stores optimal routes per service | ||||||
|  | 	bestRoutes := make(map[string]Route) | ||||||
|  |  | ||||||
|  | 	// go through all routes found in the routing table and collapse them to optimal routes | ||||||
|  | 	for _, route := range routes { | ||||||
|  | 		routeKey := route.Service + "@" + route.Network | ||||||
|  | 		optimal, ok := bestRoutes[routeKey] | ||||||
|  | 		if !ok { | ||||||
|  | 			bestRoutes[routeKey] = route | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		// if the current optimal route metric is higher than routing table route, replace it | ||||||
|  | 		if optimal.Metric > route.Metric { | ||||||
|  | 			bestRoutes[routeKey] = route | ||||||
|  | 			continue | ||||||
|  | 		} | ||||||
|  | 		// if the metrics are the same, prefer advertising your own route | ||||||
|  | 		if optimal.Metric == route.Metric { | ||||||
|  | 			if route.Router == r.options.Id { | ||||||
|  | 				bestRoutes[routeKey] = route | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	log.Debugf("Router advertising %d best routes out of %d", len(bestRoutes), len(routes)) | ||||||
|  |  | ||||||
| 	// build a list of events to advertise | 	// build a list of events to advertise | ||||||
| 	events := make([]*Event, len(routes)) | 	events := make([]*Event, len(bestRoutes)) | ||||||
| 	for i, route := range routes { | 	i := 0 | ||||||
|  | 	for _, route := range bestRoutes { | ||||||
| 		event := &Event{ | 		event := &Event{ | ||||||
| 			Type:      evType, | 			Type:      evType, | ||||||
| 			Timestamp: time.Now(), | 			Timestamp: time.Now(), | ||||||
| 			Route:     route, | 			Route:     route, | ||||||
| 		} | 		} | ||||||
| 		events[i] = event | 		events[i] = event | ||||||
|  | 		i++ | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return events, nil | 	return events, nil | ||||||
|   | |||||||
| @@ -18,6 +18,8 @@ type Options struct { | |||||||
| 	Network string | 	Network string | ||||||
| 	// Registry is the local registry | 	// Registry is the local registry | ||||||
| 	Registry registry.Registry | 	Registry registry.Registry | ||||||
|  | 	// Advertise is the advertising strategy | ||||||
|  | 	Advertise Strategy | ||||||
| 	// Client for calling router | 	// Client for calling router | ||||||
| 	Client client.Client | 	Client client.Client | ||||||
| } | } | ||||||
| @@ -64,12 +66,20 @@ func Registry(r registry.Registry) Option { | |||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Strategy sets route advertising strategy | ||||||
|  | func Advertise(a Strategy) Option { | ||||||
|  | 	return func(o *Options) { | ||||||
|  | 		o.Advertise = a | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| // DefaultOptions returns router default options | // DefaultOptions returns router default options | ||||||
| func DefaultOptions() Options { | func DefaultOptions() Options { | ||||||
| 	return Options{ | 	return Options{ | ||||||
| 		Id:       uuid.New().String(), | 		Id:        uuid.New().String(), | ||||||
| 		Address:  DefaultAddress, | 		Address:   DefaultAddress, | ||||||
| 		Network:  DefaultNetwork, | 		Network:   DefaultNetwork, | ||||||
| 		Registry: registry.DefaultRegistry, | 		Registry:  registry.DefaultRegistry, | ||||||
|  | 		Advertise: AdvertiseBest, | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -139,6 +139,28 @@ type Advert struct { | |||||||
| 	Events []*Event | 	Events []*Event | ||||||
| } | } | ||||||
|  |  | ||||||
|  | // Strategy is route advertisement strategy | ||||||
|  | type Strategy int | ||||||
|  |  | ||||||
|  | const ( | ||||||
|  | 	// AdvertiseAll advertises all routes to the network | ||||||
|  | 	AdvertiseAll Strategy = iota | ||||||
|  | 	// AdvertiseBest advertises optimal routes to the network | ||||||
|  | 	AdvertiseBest | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | // String returns human readable Strategy | ||||||
|  | func (s Strategy) String() string { | ||||||
|  | 	switch s { | ||||||
|  | 	case AdvertiseAll: | ||||||
|  | 		return "all" | ||||||
|  | 	case AdvertiseBest: | ||||||
|  | 		return "best" | ||||||
|  | 	default: | ||||||
|  | 		return "unknown" | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
| // NewRouter creates new Router and returns it | // NewRouter creates new Router and returns it | ||||||
| func NewRouter(opts ...Option) Router { | func NewRouter(opts ...Option) Router { | ||||||
| 	return newRouter(opts...) | 	return newRouter(opts...) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user