Added Entry type. Basic implementation of Router and Table

This commit is contained in:
Milos Gajdos 2019-06-09 23:09:38 +01:00
parent ad92e6821e
commit 9c57f32f58
No known key found for this signature in database
GPG Key ID: 8B31058CC55DFD4F
6 changed files with 237 additions and 79 deletions

View File

@ -1,6 +1,9 @@
package router
import (
"fmt"
"strings"
"github.com/google/uuid"
"github.com/micro/go-micro/registry"
"github.com/micro/go-micro/registry/gossip"
@ -45,25 +48,25 @@ func (r *router) Options() Options {
// Add adds new entry into routing table with given options.
// It returns error if the entry could not be added.
func (r *router) Add(e *Entry, opts ...RouteOption) error {
return nil
func (r *router) Add(e Entry) error {
return r.table.Add(e)
}
// Remove removes entry from the routing table.
// It returns error if either the entry could not be removed or it does not exist.
func (r *router) Remove(e *Entry) error {
return nil
func (r *router) Remove(e Entry) error {
return r.table.Remove(e)
}
// Update updates an entry in the router's routing table
// It returns error if the entry was not found or it failed to be updated.
func (r *router) Update(e *Entry) error {
return nil
func (r *router) Update(opts ...EntryOption) error {
return r.table.Update(opts...)
}
// Lookup makes a query lookup and returns all matching entries
func (r *router) Lookup(q Query) ([]*Entry, error) {
return nil, nil
return nil, ErrNotImplemented
}
// Table returns routing table
@ -83,5 +86,16 @@ func (r *router) Address() string {
// String prints debugging information about router
func (r *router) String() string {
return ""
sb := &strings.Builder{}
s := fmt.Sprintf("Router Local Address: %s\n", r.opts.Address)
sb.WriteString(s)
s = fmt.Sprintf("Router Network Address: %s\n", r.opts.Network)
sb.WriteString(s)
s = fmt.Sprintf("Routing table size: %d\n", r.opts.Table.Size())
sb.WriteString(s)
return sb.String()
}

89
router/entry.go Normal file
View File

@ -0,0 +1,89 @@
package router
// AddPolicy defines routing table addition policy
type AddPolicy int
const (
// Override overrides existing routing table entry
OverrideIfExists AddPolicy = iota
// ErrIfExists returns error if the entry already exists
ErrIfExists
)
// EntryOptions defines micro network routing table entry options
type EntryOptions struct {
// DestAddr is destination address
DestAddr string
// Hop is the next route hop
Hop Router
// SrcAddr defines local routing address
// On local networkss, this will be the address of local router
SrcAddr string
// Metric is route cost metric
Metric int
// Policy defines entry addition policy
Policy AddPolicy
}
// DestAddr sets destination address
func DestAddr(a string) EntryOption {
return func(o *EntryOptions) {
o.DestAddr = a
}
}
// Hop allows to set the route entry options
func Hop(r Router) EntryOption {
return func(o *EntryOptions) {
o.Hop = r
}
}
// SrcAddr sets source address
func SrcAddr(a string) EntryOption {
return func(o *EntryOptions) {
o.SrcAddr = a
}
}
// Metric sets entry metric
func Metric(m int) EntryOption {
return func(o *EntryOptions) {
o.Metric = m
}
}
// AddEntryPolicy sets add entry policy
func AddEntryPolicy(p AddPolicy) EntryOption {
return func(o *EntryOptions) {
o.Policy = p
}
}
// Entry is routing table entry
type Entry interface {
// Options returns entry options
Options() EntryOptions
}
type entry struct {
opts EntryOptions
}
// NewEntry returns new routing table entry
func NewEntry(opts ...EntryOption) Entry {
eopts := EntryOptions{}
for _, o := range opts {
o(&eopts)
}
return &entry{
opts: eopts,
}
}
// Options returns entry options
func (e *entry) Options() EntryOptions {
return e.opts
}

View File

@ -45,27 +45,3 @@ func RoutingTable(t Table) Option {
o.Table = t
}
}
// RouteOptions allows to specify routing table options
type RouteOptions struct {
// NetID is network ID
NetID string
// Metric is route metric
Metric int
// COntext allows to specify other arbitrary options
Context context.Context
}
// NetID allows to set micro network ID
func NetID(id string) RouteOption {
return func(o *RouteOptions) {
o.NetID = id
}
}
// Metric allows to set route cost metric
func Metric(m int) RouteOption {
return func(o *RouteOptions) {
o.Metric = m
}
}

View File

@ -1,27 +1,27 @@
package router
// Policy defines query policy
type QueryPolicy int
// LookupPolicy defines query policy
type LookupPolicy int
const (
// DiscardNoRoute discards query when no rout is found
DiscardNoRoute QueryPolicy = iota
// ClosestMatch returns closest match to query
// DiscardNoRoute discards query when no route is found
DiscardNoRoute LookupPolicy = iota
// ClosestMatch returns closest match to supplied query
ClosestMatch
)
// QueryOptions allow to define routing table query options
type QueryOptions struct {
// Route allows to set route options
Route *RouteOptions
Route *EntryOptions
// Service is micro service name
Service string
// Policy defines query lookup policy
Policy QueryPolicy
Policy LookupPolicy
}
// Route allows to set the route query options
func Route(r *RouteOptions) QueryOption {
// EntryOpts allows to set the route query options
func EntryOpts(r *EntryOptions) QueryOption {
return func(o *QueryOptions) {
o.Route = r
}
@ -34,8 +34,8 @@ func Service(s string) QueryOption {
}
}
// Policy allows to define query lookup policy
func Policy(p QueryPolicy) QueryOption {
// QueryLookupPolicy allows to define query lookup policy
func QueryLookupPolicy(p LookupPolicy) QueryOption {
return func(o *QueryOptions) {
o.Policy = p
}

View File

@ -8,18 +8,18 @@ type Router interface {
// Options returns Router options
Options() Options
// Add adds new entry into routing table
Add(*Entry, ...RouteOption) error
Add(Entry) error
// Remove removes entry from the routing table
Remove(*Entry) error
Remove(Entry) error
// Update updates entry in the routing table
Update(*Entry) error
Update(...EntryOption) error
// Lookup queries the routing table and returns matching entries
Lookup(Query) ([]*Entry, error)
// Table returns routing table
Table() Table
// Address is Router adddress
// Address returns the router bind adddress
Address() string
// Network defines network router is in
// Network returns router's micro network bind address
Network() string
// String implemens fmt.Stringer interface
String() string
@ -31,13 +31,13 @@ type RIB interface {
String() string
}
// Option used by the Router
// Option used by the router
type Option func(*Options)
// RouteOption is used by Router for adding routing table entries
type RouteOption func(*RouteOptions)
// EntryOption is used to define routing entry options
type EntryOption func(*EntryOptions)
// QueryOption is used to defined routing table lookup query
// QueryOption is used to define query options
type QueryOption func(*QueryOptions)
// NewRouter creates new Router and returns it

View File

@ -2,7 +2,12 @@ package router
import (
"errors"
"fmt"
"hash/fnv"
"strings"
"sync"
"github.com/olekukonko/tablewriter"
)
var (
@ -10,77 +15,151 @@ var (
ErrRouteNotFound = errors.New("route not found")
// ErrDuplicateRoute is return when route already exists
ErrDuplicateRoute = errors.New("duplicate route")
// ErrNotImplemented is returned when some functionality has not been implemented
ErrNotImplemented = errors.New("not implemented")
)
// Table is routing table
type Table interface {
// Add adds new route to the table
Add(*Entry) error
Add(Entry) error
// Remove removes route from the table
Remove(*Entry) error
Remove(Entry) error
// Update updates route in the table
Update(*Entry) error
Update(...EntryOption) error
// Lookup looks up routes in the table
Lookup(Query) ([]*Entry, error)
Lookup(Query) ([]Entry, error)
// Size returns the size of the table
Size() int
// String prints the routing table
String() string
}
// Entry is micro network routing table entry
type Entry struct {
// Addr is destination address
Addr string
// NetID is micro network ID
NetID string
// Hop is the next route hop
Hop Router
// Metric is route cost metric
Metric int
}
// table is routing table
// It maps service name to routes
type table struct {
// m stores routing table map
m map[string][]Entry
m map[string]map[uint64]Entry
sync.RWMutex
}
// NewTable creates new routing table and returns it
func NewTable() Table {
return &table{
m: make(map[string][]Entry),
m: make(map[string]map[uint64]Entry),
}
}
// Add adds new routing entry
func (t *table) Add(e *Entry) error {
return nil
func (t *table) Add(e Entry) error {
t.Lock()
defer t.Unlock()
destAddr := e.Options().DestAddr
h := fnv.New64()
h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address()))
if _, ok := t.m[destAddr]; !ok {
// create new map for DestAddr routes
t.m[destAddr] = make(map[uint64]Entry)
t.m[destAddr][h.Sum64()] = e
return nil
}
if _, ok := t.m[destAddr][h.Sum64()]; ok && e.Options().Policy == OverrideIfExists {
t.m[destAddr][h.Sum64()] = e
return nil
}
return ErrDuplicateRoute
}
// Remove removes entry from the routing table
func (t *table) Remove(e *Entry) error {
func (t *table) Remove(e Entry) error {
t.Lock()
defer t.Unlock()
destAddr := e.Options().DestAddr
h := fnv.New64()
h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address()))
if _, ok := t.m[destAddr]; !ok {
return ErrRouteNotFound
} else {
delete(t.m[destAddr], h.Sum64())
return nil
}
return nil
}
// Update updates routin entry
func (t *table) Update(e *Entry) error {
return nil
// Update updates routing entry
func (t *table) Update(opts ...EntryOption) error {
t.Lock()
defer t.Unlock()
e := NewEntry(opts...)
destAddr := e.Options().DestAddr
h := fnv.New64()
h.Write([]byte(e.Options().DestAddr + e.Options().Hop.Address()))
if _, ok := t.m[destAddr]; !ok {
return ErrRouteNotFound
}
if _, ok := t.m[destAddr][h.Sum64()]; ok {
t.m[destAddr][h.Sum64()] = e
return nil
}
return ErrRouteNotFound
}
// Lookup looks up entry in the routing table
func (t *table) Lookup(q Query) ([]*Entry, error) {
return nil, nil
func (t *table) Lookup(q Query) ([]Entry, error) {
return nil, ErrNotImplemented
}
// Size returns the size of the routing table
func (t *table) Size() int {
t.RLock()
defer t.RUnlock()
return len(t.m)
}
// String returns text representation of routing table
func (t *table) String() string {
return ""
t.RLock()
defer t.RUnlock()
// this will help us build routing table string
sb := &strings.Builder{}
// create nice table printing structure
table := tablewriter.NewWriter(sb)
table.SetHeader([]string{"Dest", "Hop", "Src", "Metric"})
var destAddr, prevAddr string
for _, entries := range t.m {
for _, entry := range entries {
destAddr = entry.Options().DestAddr
// we want to avoid printing the same dest address
if prevAddr == destAddr {
destAddr = ""
}
strEntry := []string{
destAddr,
entry.Options().Hop.Address(),
fmt.Sprintf("%d", entry.Options().SrcAddr),
fmt.Sprintf("%d", entry.Options().Metric),
}
table.Append(strEntry)
prevAddr = destAddr
}
}
return sb.String()
}