diff options
author | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2015-08-26 18:11:38 +0900 |
---|---|---|
committer | Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp> | 2015-09-01 19:42:02 +0900 |
commit | cc51c48a4934bde8f5a5555632633c3c8486b797 (patch) | |
tree | 14998dac3531e6a609bb414d2816f7f7d2ba1d5f /zebra/zapi.go | |
parent | f8d437ec0ea65656ca4c6d81ec48fe0f7099c60e (diff) |
zebra: distribute routes from zebra
Signed-off-by: Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>
Diffstat (limited to 'zebra/zapi.go')
-rw-r--r-- | zebra/zapi.go | 149 |
1 files changed, 134 insertions, 15 deletions
diff --git a/zebra/zapi.go b/zebra/zapi.go index c014531c..08fcf80d 100644 --- a/zebra/zapi.go +++ b/zebra/zapi.go @@ -226,7 +226,7 @@ func NewClient(network, address string, typ ROUTE_TYPE) (*Client, error) { log.Error("failed to read header: ", err) return err } - + log.Debugf("read header from zebra: %v", headerBuf) hd := &Header{} err = hd.DecodeFromBytes(headerBuf) if err != nil { @@ -239,7 +239,7 @@ func NewClient(network, address string, typ ROUTE_TYPE) (*Client, error) { log.Error("failed to read body: ", err) return err } - + log.Debugf("read body from zebra: %v", bodyBuf) m, err := ParseMessage(hd, bodyBuf) if err != nil { log.Warn("failed to parse message: ", err) @@ -272,6 +272,12 @@ func (c *Client) Send(m *Message) { } func (c *Client) SendCommand(command API_TYPE, body Body) error { + + log.WithFields(log.Fields{ + "Topic": "Zebra", + "Command": command.String(), + "Body": body, + }).Debug("send command to zebra") m := &Message{ Header: Header{ Len: HEADER_SIZE, @@ -288,7 +294,7 @@ func (c *Client) SendCommand(command API_TYPE, body Body) error { func (c *Client) SendHello() error { if c.redistDefault > 0 { body := &HelloBody{ - Redist: c.redistDefault, + RedistDefault: c.redistDefault, } return c.SendCommand(HELLO, body) } @@ -303,6 +309,24 @@ func (c *Client) SendInterfaceAdd() error { return c.SendCommand(INTERFACE_ADD, nil) } +func (c *Client) SendRedistribute() error { + for i := ROUTE_SYSTEM; i < ROUTE_MAX; i++ { + if c.redistDefault != i { + body := &RedistributeBody{ + Redist: i, + } + if e := c.SendCommand(REDISTRIBUTE_ADD, body); e != nil { + return e + } + } + } + + if e := c.SendCommand(REDISTRIBUTE_DEFAULT_ADD, nil); e != nil { + return e + } + return nil +} + func (c *Client) Close() error { close(c.outgoing) return c.conn.Close() @@ -341,15 +365,28 @@ type Body interface { } type HelloBody struct { - Redist ROUTE_TYPE + RedistDefault ROUTE_TYPE } func (b *HelloBody) DecodeFromBytes(data []byte) error { - b.Redist = ROUTE_TYPE(data[0]) + b.RedistDefault = ROUTE_TYPE(data[0]) return nil } func (b *HelloBody) Serialize() ([]byte, error) { + return []byte{uint8(b.RedistDefault)}, nil +} + +type RedistributeBody struct { + Redist ROUTE_TYPE +} + +func (b *RedistributeBody) DecodeFromBytes(data []byte) error { + b.Redist = ROUTE_TYPE(data[0]) + return nil +} + +func (b *RedistributeBody) Serialize() ([]byte, error) { return []byte{uint8(b.Redist)}, nil } @@ -471,16 +508,7 @@ type IPRouteBody struct { Ifindexs []uint32 Distance uint8 Metric uint32 -} - -func (b *IPRouteBody) DecodeFromBytes(data []byte) error { - b.Type = ROUTE_TYPE(data[0]) - b.Flags = FLAG(data[1]) - b.Message = data[2] - b.SAFI = SAFI(data[3]) - b.Prefix = data[3:7] - b.PrefixLength = data[7] - return nil + Api API_TYPE } func (b *IPRouteBody) Serialize() ([]byte, error) { @@ -537,6 +565,94 @@ func (b *IPRouteBody) Serialize() ([]byte, error) { return buf, nil } +func (b *IPRouteBody) DecodeFromBytes(data []byte) error { + + isV4 := b.Api == IPV4_ROUTE_ADD || b.Api == IPV4_ROUTE_DELETE + var addrLen uint8 = net.IPv4len + if !isV4 { + addrLen = net.IPv6len + } + + b.Type = ROUTE_TYPE(data[0]) + b.Flags = FLAG(data[1]) + b.Message = data[2] + b.PrefixLength = data[3] + b.SAFI = SAFI(SAFI_UNICAST) + + if b.PrefixLength > addrLen*8 { + return fmt.Errorf("prefix length is greater than %d", addrLen*8) + } + + byteLen := int((b.PrefixLength + 7) / 8) + + curPos := 4 + buf := make([]byte, addrLen) + copy(buf, data[curPos:curPos+byteLen]) + + if isV4 { + b.Prefix = net.IP(buf).To4() + } else { + b.Prefix = net.IP(buf).To16() + } + + curPos += byteLen + + rest := 0 + var numNexthop int + if b.Message&MESSAGE_NEXTHOP > 0 { + numNexthop = int(data[curPos]) + // rest = numNexthop(1) + (nexthop(4 or 16) + placeholder(1) + ifindex(4)) * numNexthop + rest += 1 + numNexthop*(int(addrLen)+5) + } + + if b.Message&MESSAGE_DISTANCE > 0 { + // distance(1) + rest += 1 + } + + if b.Message&MESSAGE_METRIC > 0 { + // metric(4) + rest += 4 + } + + if len(data[curPos:]) != rest { + return fmt.Errorf("message length invalid") + } + + b.Nexthops = []net.IP{} + b.Ifindexs = []uint32{} + + if b.Message&MESSAGE_NEXTHOP > 0 { + curPos += 1 + for i := 0; i < numNexthop; i++ { + addr := data[curPos : curPos+int(addrLen)] + var nexthop net.IP + if isV4 { + nexthop = net.IP(addr).To4() + } else { + nexthop = net.IP(addr).To16() + } + b.Nexthops = append(b.Nexthops, nexthop) + + // skip nexthop and 1byte place holder + curPos += int(addrLen + 1) + ifidx := binary.BigEndian.Uint32(data[curPos : curPos+4]) + b.Ifindexs = append(b.Ifindexs, ifidx) + curPos += 4 + } + } + + if b.Message&MESSAGE_DISTANCE > 0 { + b.Distance = data[curPos] + } + if b.Message&MESSAGE_METRIC > 0 { + curPos += 1 + b.Metric = binary.BigEndian.Uint32(data[curPos : curPos+4]) + } + + return nil +} + type Message struct { Header Header Body Body @@ -569,6 +685,9 @@ func ParseMessage(hdr *Header, data []byte) (*Message, error) { m.Body = &InterfaceAddressUpdateBody{} case ROUTER_ID_UPDATE: m.Body = &RouterIDUpdateBody{} + 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) default: return nil, fmt.Errorf("Unknown zapi command: %d", m.Header.Command) } |