diff options
Diffstat (limited to 'zebra')
-rw-r--r-- | zebra/zapi.go | 244 | ||||
-rw-r--r-- | zebra/zapi_test.go | 126 |
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) +} |