summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--zebra/zapi.go244
-rw-r--r--zebra/zapi_test.go126
2 files changed, 357 insertions, 13 deletions
diff --git a/zebra/zapi.go b/zebra/zapi.go
index 08fcf80d..d3e6abf0 100644
--- a/zebra/zapi.go
+++ b/zebra/zapi.go
@@ -327,6 +327,21 @@ func (c *Client) SendRedistribute() error {
return nil
}
+func (c *Client) SendRedistributeDelete(t ROUTE_TYPE) error {
+
+ if t < ROUTE_MAX {
+ body := &RedistributeBody{
+ Redist: t,
+ }
+ if e := c.SendCommand(REDISTRIBUTE_DELETE, body); e != nil {
+ return e
+ }
+ } else {
+ fmt.Errorf("unknown route type: %d", t)
+ }
+ return nil
+}
+
func (c *Client) Close() error {
close(c.outgoing)
return c.conn.Close()
@@ -585,9 +600,9 @@ func (b *IPRouteBody) DecodeFromBytes(data []byte) error {
byteLen := int((b.PrefixLength + 7) / 8)
- curPos := 4
+ pos := 4
buf := make([]byte, addrLen)
- copy(buf, data[curPos:curPos+byteLen])
+ copy(buf, data[pos:pos+byteLen])
if isV4 {
b.Prefix = net.IP(buf).To4()
@@ -595,12 +610,12 @@ func (b *IPRouteBody) DecodeFromBytes(data []byte) error {
b.Prefix = net.IP(buf).To16()
}
- curPos += byteLen
+ pos += byteLen
rest := 0
var numNexthop int
if b.Message&MESSAGE_NEXTHOP > 0 {
- numNexthop = int(data[curPos])
+ numNexthop = int(data[pos])
// rest = numNexthop(1) + (nexthop(4 or 16) + placeholder(1) + ifindex(4)) * numNexthop
rest += 1 + numNexthop*(int(addrLen)+5)
}
@@ -615,7 +630,7 @@ func (b *IPRouteBody) DecodeFromBytes(data []byte) error {
rest += 4
}
- if len(data[curPos:]) != rest {
+ if len(data[pos:]) != rest {
return fmt.Errorf("message length invalid")
}
@@ -623,9 +638,9 @@ func (b *IPRouteBody) DecodeFromBytes(data []byte) error {
b.Ifindexs = []uint32{}
if b.Message&MESSAGE_NEXTHOP > 0 {
- curPos += 1
+ pos += 1
for i := 0; i < numNexthop; i++ {
- addr := data[curPos : curPos+int(addrLen)]
+ addr := data[pos : pos+int(addrLen)]
var nexthop net.IP
if isV4 {
nexthop = net.IP(addr).To4()
@@ -635,24 +650,221 @@ func (b *IPRouteBody) DecodeFromBytes(data []byte) error {
b.Nexthops = append(b.Nexthops, nexthop)
// skip nexthop and 1byte place holder
- curPos += int(addrLen + 1)
- ifidx := binary.BigEndian.Uint32(data[curPos : curPos+4])
+ pos += int(addrLen + 1)
+ ifidx := binary.BigEndian.Uint32(data[pos : pos+4])
b.Ifindexs = append(b.Ifindexs, ifidx)
- curPos += 4
+ pos += 4
}
}
if b.Message&MESSAGE_DISTANCE > 0 {
- b.Distance = data[curPos]
+ b.Distance = data[pos]
}
if b.Message&MESSAGE_METRIC > 0 {
- curPos += 1
- b.Metric = binary.BigEndian.Uint32(data[curPos : curPos+4])
+ pos += 1
+ b.Metric = binary.BigEndian.Uint32(data[pos : pos+4])
}
return nil
}
+func (b *IPRouteBody) String() string {
+ s := fmt.Sprintf("type: %s, flags: %s, message: %d, prefix: %s, length: %d, nexthop: %s, ifindex: %d, distance: %d, metric: %d",
+ b.Type.String(), b.Flags.String(), b.Message, b.Prefix.String(), b.PrefixLength, b.Nexthops[0].String(), b.Ifindexs[0], b.Distance, b.Metric)
+ return s
+}
+
+type NexthopLookupBody struct {
+ Api API_TYPE
+ Addr net.IP
+ Metric uint32
+ Nexthops []*Nexthop
+}
+
+type Nexthop struct {
+ Ifname string
+ Ifindex uint32
+ Type NEXTHOP_FLAG
+ Addr net.IP
+}
+
+func (n *Nexthop) String() string {
+ s := fmt.Sprintf("type: %s, addr: %s, ifindex: %d, ifname: %s", n.Type.String(), n.Addr.String(), n.Ifindex, n.Ifname)
+ return s
+}
+
+func (b *NexthopLookupBody) Serialize() ([]byte, error) {
+
+ isV4 := b.Api == IPV4_NEXTHOP_LOOKUP
+ buf := make([]byte, 0)
+
+ if isV4 {
+ buf = append(buf, b.Addr.To4()...)
+ } else {
+ buf = append(buf, b.Addr.To16()...)
+ }
+ return buf, nil
+}
+
+func (b *NexthopLookupBody) DecodeFromBytes(data []byte) error {
+
+ isV4 := b.Api == IPV4_NEXTHOP_LOOKUP
+ var addrLen uint8 = net.IPv4len
+ if !isV4 {
+ addrLen = net.IPv6len
+ }
+
+ if len(data) < int(addrLen) {
+ return fmt.Errorf("message length invalid")
+ }
+
+ buf := make([]byte, addrLen)
+ copy(buf, data[0:addrLen])
+ pos := addrLen
+
+ if isV4 {
+ b.Addr = net.IP(buf).To4()
+ } else {
+ b.Addr = net.IP(buf).To16()
+ }
+
+ if len(data[pos:]) > int(1+addrLen) {
+ b.Metric = binary.BigEndian.Uint32(data[pos : pos+4])
+ pos += 4
+ nexthopNum := int(data[pos])
+ b.Nexthops = []*Nexthop{}
+
+ if nexthopNum > 0 {
+ pos += 1
+ for i := 0; i < nexthopNum; i++ {
+ nh := &Nexthop{}
+ nh.Type = NEXTHOP_FLAG(data[pos])
+ pos += 1
+
+ switch nh.Type {
+ case NEXTHOP_IPV4, NEXTHOP_IPV6:
+ b := make([]byte, addrLen)
+ copy(b, data[pos:pos+addrLen])
+ if isV4 {
+ nh.Addr = net.IP(b).To4()
+ } else {
+ nh.Addr = net.IP(b).To16()
+ }
+ pos += addrLen
+
+ case NEXTHOP_IPV4_IFINDEX, NEXTHOP_IPV6_IFINDEX, NEXTHOP_IPV6_IFNAME:
+ b := make([]byte, addrLen)
+ copy(b, data[pos:pos+addrLen])
+ if isV4 {
+ nh.Addr = net.IP(b).To4()
+ } else {
+ nh.Addr = net.IP(b).To16()
+ }
+ pos += addrLen
+ nh.Ifindex = binary.BigEndian.Uint32(data[pos : pos+4])
+ pos += 4
+
+ case NEXTHOP_IFINDEX, NEXTHOP_IFNAME:
+ nh.Ifindex = binary.BigEndian.Uint32(data[pos : pos+4])
+ pos += 4
+ }
+ b.Nexthops = append(b.Nexthops, nh)
+ }
+ }
+ }
+
+ return nil
+}
+
+func (b *NexthopLookupBody) String() string {
+ s := fmt.Sprintf("addr: %s, metric: %d", b.Addr, b.Metric)
+ if len(b.Nexthops) > 0 {
+ for _, nh := range b.Nexthops {
+ s = s + fmt.Sprintf(", nexthop:{%s}", nh.String())
+ }
+ }
+ return s
+}
+
+type ImportLookupBody struct {
+ Api API_TYPE
+ PrefixLength uint8
+ Prefix net.IP
+ Addr net.IP
+ Metric uint32
+ Nexthops []*Nexthop
+}
+
+func (b *ImportLookupBody) Serialize() ([]byte, error) {
+ buf := make([]byte, 1)
+ buf[0] = b.PrefixLength
+ buf = append(buf, b.Addr.To4()...)
+ return buf, nil
+}
+
+func (b *ImportLookupBody) DecodeFromBytes(data []byte) error {
+
+ var addrLen uint8 = net.IPv4len
+
+ if len(data) < int(addrLen) {
+ return fmt.Errorf("message length invalid")
+ }
+
+ buf := make([]byte, addrLen)
+ copy(buf, data[0:addrLen])
+ pos := addrLen
+
+ b.Addr = net.IP(buf).To4()
+
+ if len(data[pos:]) > int(1+addrLen) {
+ b.Metric = binary.BigEndian.Uint32(data[pos : pos+4])
+ pos += 4
+ nexthopNum := int(data[pos])
+ b.Nexthops = []*Nexthop{}
+ if nexthopNum > 0 {
+ pos += 1
+ for i := 0; i < nexthopNum; i++ {
+ nh := &Nexthop{}
+ nh.Type = NEXTHOP_FLAG(data[pos])
+ pos += 1
+
+ switch nh.Type {
+ case NEXTHOP_IPV4:
+ b := make([]byte, addrLen)
+ copy(b, data[pos:pos+addrLen])
+ nh.Addr = net.IP(b).To4()
+ pos += addrLen
+
+ case NEXTHOP_IPV4_IFINDEX:
+ b := make([]byte, addrLen)
+ copy(b, data[pos:pos+addrLen])
+ nh.Addr = net.IP(b).To4()
+ pos += addrLen
+ nh.Ifindex = binary.BigEndian.Uint32(data[pos : pos+4])
+ pos += 4
+
+ case NEXTHOP_IFINDEX, NEXTHOP_IFNAME:
+ nh.Ifindex = binary.BigEndian.Uint32(data[pos : pos+4])
+ pos += 4
+ }
+ b.Nexthops = append(b.Nexthops, nh)
+ }
+ }
+ }
+
+ return nil
+}
+
+func (b *ImportLookupBody) String() string {
+ s := fmt.Sprintf("addr: %s, metric: %d", b.Addr, b.Metric)
+ if len(b.Nexthops) > 0 {
+ for _, nh := range b.Nexthops {
+ s = s + fmt.Sprintf(", nexthop:{%s}", nh.String())
+ }
+ }
+ return s
+}
+
type Message struct {
Header Header
Body Body
@@ -688,6 +900,12 @@ func ParseMessage(hdr *Header, data []byte) (*Message, error) {
case IPV4_ROUTE_ADD, IPV6_ROUTE_ADD, IPV4_ROUTE_DELETE, IPV6_ROUTE_DELETE:
m.Body = &IPRouteBody{Api: m.Header.Command}
log.Debugf("ipv4/v6 route add/delete message received: %v", data)
+ case IPV4_NEXTHOP_LOOKUP, IPV6_NEXTHOP_LOOKUP:
+ m.Body = &NexthopLookupBody{Api: m.Header.Command}
+ log.Debugf("ipv4/v6 nexthop lookup received: %v", data)
+ case IPV4_IMPORT_LOOKUP:
+ m.Body = &ImportLookupBody{Api: m.Header.Command}
+ log.Debugf("ipv4 import lookup message received: %v", data)
default:
return nil, fmt.Errorf("Unknown zapi command: %d", m.Header.Command)
}
diff --git a/zebra/zapi_test.go b/zebra/zapi_test.go
index fcb912a1..be464235 100644
--- a/zebra/zapi_test.go
+++ b/zebra/zapi_test.go
@@ -318,3 +318,129 @@ func Test_IPRouteBody_IPv6(t *testing.T) {
err = r.DecodeFromBytes(buf)
assert.Equal(nil, err)
}
+
+func Test_NexthopLookupBody(t *testing.T) {
+ assert := assert.New(t)
+
+ //ipv4
+ //DecodeFromBytes
+ pos := 0
+ buf := make([]byte, 18)
+ ip := net.ParseIP("192.168.50.0").To4()
+ copy(buf[0:4], []byte(ip))
+ pos += 4
+ binary.BigEndian.PutUint32(buf[pos:], 10)
+ pos += 4
+ buf[pos] = byte(1)
+ pos += 1
+ buf[pos] = byte(4)
+ pos += 1
+ ip = net.ParseIP("172.16.1.101").To4()
+ copy(buf[pos:pos+4], []byte(ip))
+ pos += 4
+ binary.BigEndian.PutUint32(buf[pos:], 3)
+
+ b := &NexthopLookupBody{Api: IPV4_NEXTHOP_LOOKUP}
+ err := b.DecodeFromBytes(buf)
+ assert.Equal(nil, err)
+ assert.Equal("192.168.50.0", b.Addr.String())
+ assert.Equal(uint32(10), b.Metric)
+ assert.Equal(uint32(3), b.Nexthops[0].Ifindex)
+ assert.Equal(NEXTHOP_FLAG(4), b.Nexthops[0].Type)
+ assert.Equal("172.16.1.101", b.Nexthops[0].Addr.String())
+
+ //Serialize
+ buf, err = b.Serialize()
+ ip = net.ParseIP("192.168.50.0").To4()
+ assert.Equal(nil, err)
+ assert.Equal([]byte(ip)[0:4], buf[0:4])
+
+ // length invalid
+ buf = make([]byte, 3)
+ b = &NexthopLookupBody{Api: IPV4_NEXTHOP_LOOKUP}
+ err = b.DecodeFromBytes(buf)
+ assert.NotEqual(nil, err)
+
+ //ipv6
+ //DecodeFromBytes
+ pos = 0
+ buf = make([]byte, 46)
+ ip = net.ParseIP("2001:db8:0:f101::").To16()
+ copy(buf[0:16], []byte(ip))
+ pos += 16
+ binary.BigEndian.PutUint32(buf[pos:], 10)
+ pos += 4
+ buf[pos] = byte(1)
+ pos += 1
+ buf[pos] = byte(4)
+ pos += 1
+ ip = net.ParseIP("2001:db8:0:1111::1").To16()
+ copy(buf[pos:pos+16], []byte(ip))
+ pos += 16
+ binary.BigEndian.PutUint32(buf[pos:], 3)
+
+ b = &NexthopLookupBody{Api: IPV6_NEXTHOP_LOOKUP}
+ err = b.DecodeFromBytes(buf)
+ assert.Equal(nil, err)
+ assert.Equal("2001:db8:0:f101::", b.Addr.String())
+ assert.Equal(uint32(10), b.Metric)
+ assert.Equal(uint32(3), b.Nexthops[0].Ifindex)
+ assert.Equal(NEXTHOP_FLAG(4), b.Nexthops[0].Type)
+ assert.Equal("2001:db8:0:1111::1", b.Nexthops[0].Addr.String())
+
+ //Serialize
+ buf, err = b.Serialize()
+ ip = net.ParseIP("2001:db8:0:f101::").To16()
+ assert.Equal(nil, err)
+ assert.Equal([]byte(ip)[0:16], buf[0:16])
+
+ // length invalid
+ buf = make([]byte, 15)
+ b = &NexthopLookupBody{Api: IPV6_NEXTHOP_LOOKUP}
+ err = b.DecodeFromBytes(buf)
+ assert.NotEqual(nil, err)
+}
+
+func Test_ImportLookupBody(t *testing.T) {
+ assert := assert.New(t)
+
+ //DecodeFromBytes
+ pos := 0
+ buf := make([]byte, 18)
+ ip := net.ParseIP("192.168.50.0").To4()
+ copy(buf[0:4], []byte(ip))
+ pos += 4
+ binary.BigEndian.PutUint32(buf[pos:], 10)
+ pos += 4
+ buf[pos] = byte(1)
+ pos += 1
+ buf[pos] = byte(4)
+ pos += 1
+ ip = net.ParseIP("172.16.1.101").To4()
+ copy(buf[pos:pos+4], []byte(ip))
+ pos += 4
+ binary.BigEndian.PutUint32(buf[pos:], 3)
+
+ b := &ImportLookupBody{Api: IPV4_IMPORT_LOOKUP}
+ err := b.DecodeFromBytes(buf)
+ assert.Equal(nil, err)
+ assert.Equal("192.168.50.0", b.Addr.String())
+ assert.Equal(uint32(10), b.Metric)
+ assert.Equal(uint32(3), b.Nexthops[0].Ifindex)
+ assert.Equal(NEXTHOP_FLAG(4), b.Nexthops[0].Type)
+ assert.Equal("172.16.1.101", b.Nexthops[0].Addr.String())
+
+ //Serialize
+ b.PrefixLength = uint8(24)
+ buf, err = b.Serialize()
+ ip = net.ParseIP("192.168.50.0").To4()
+ assert.Equal(nil, err)
+ assert.Equal(uint8(24), buf[0])
+ assert.Equal([]byte(ip)[0:4], buf[1:5])
+
+ // length invalid
+ buf = make([]byte, 3)
+ b = &ImportLookupBody{Api: IPV4_IMPORT_LOOKUP}
+ err = b.DecodeFromBytes(buf)
+ assert.NotEqual(nil, err)
+}