From 017846eae9946a637608dd2516ac528bfd2b348c Mon Sep 17 00:00:00 2001
From: Julian Kornberger <jk+github@digineo.de>
Date: Sat, 29 Dec 2018 16:30:04 +0100
Subject: [PATCH] Wrap errors (#161)

Package errors provides simple error handling primitives.
Read more on https://github.com/pkg/errors
---
 config/server.go                              |  9 ++--
 net/prefix.go                                 |  3 +-
 protocols/bgp/packet/decoder.go               | 19 +++----
 protocols/bgp/packet/mp_reach_nlri.go         |  3 +-
 protocols/bgp/packet/nlri.go                  |  5 +-
 protocols/bgp/packet/path_attributes.go       | 53 ++++++++++---------
 protocols/bgp/server/bmp_router.go            |  5 +-
 protocols/bgp/server/bmp_server.go            |  5 +-
 protocols/bgp/server/fsm.go                   | 11 ++--
 protocols/bgp/server/fsm_established.go       |  5 +-
 protocols/bgp/server/server.go                |  6 +--
 protocols/bgp/server/update_helper.go         |  4 +-
 protocols/bgp/server/update_helper_test.go    |  9 +++-
 protocols/bmp/packet/decode.go                | 18 ++++---
 protocols/bmp/packet/initiation_message.go    |  5 +-
 protocols/bmp/packet/peer_down.go             |  6 +--
 protocols/bmp/packet/peer_up.go               | 12 ++---
 protocols/bmp/packet/route_mirroring.go       |  7 +--
 protocols/bmp/packet/route_monitoring.go      |  4 +-
 protocols/bmp/packet/stats_report.go          |  6 +--
 protocols/bmp/packet/termination_message.go   |  5 +-
 protocols/bmp/server/server.go                |  5 +-
 protocols/device/server.go                    |  7 +--
 protocols/device/server_linux.go              | 17 +++---
 protocols/isis/packet/csnp.go                 |  6 +--
 protocols/isis/packet/header.go               |  4 +-
 protocols/isis/packet/hello.go                | 10 ++--
 protocols/isis/packet/isis.go                 |  7 +--
 protocols/isis/packet/lsp.go                  |  6 +--
 protocols/isis/packet/lsp_entry.go            |  4 +-
 protocols/isis/packet/psnp.go                 |  6 +--
 protocols/isis/packet/tlv.go                  |  6 +--
 protocols/isis/packet/tlv_area_addresses.go   |  6 +--
 protocols/isis/packet/tlv_checksum.go         |  4 +-
 protocols/isis/packet/tlv_dynamic_hostname.go |  4 +-
 .../isis/packet/tlv_ip_interface_address.go   |  4 +-
 protocols/isis/packet/tlv_is_neighbors.go     |  4 +-
 protocols/isis/packet/tlv_p2p_adj_state.go    |  4 +-
 .../isis/packet/tlv_protocols_supported.go    |  4 +-
 protocols/isis/packet/tlv_unknown.go          |  4 +-
 protocols/netlink/netlink_writer.go           |  5 +-
 routingtable/adjRIBOut/adj_rib_out.go         |  3 +-
 util/decode/decode.go                         |  5 +-
 util/decoder/decoder.go                       |  5 +-
 44 files changed, 179 insertions(+), 151 deletions(-)

diff --git a/config/server.go b/config/server.go
index 3e7e8be8..16211895 100644
--- a/config/server.go
+++ b/config/server.go
@@ -6,6 +6,7 @@ import (
 	"net"
 	"strings"
 
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -29,7 +30,7 @@ func (g *Global) SetDefaultGlobalConfigValues() error {
 	if g.RouterID == 0 {
 		rtrid, err := generateRouterID()
 		if err != nil {
-			return fmt.Errorf("Unable to determine router ID: %v", err)
+			return errors.Wrap(err, "Unable to determine router ID")
 		}
 		g.RouterID = rtrid
 	}
@@ -64,7 +65,7 @@ func _getHighestIP(ifs []net.Interface) (net.IP, error) {
 	for _, iface := range ifs {
 		addrs, err := iface.Addrs()
 		if err != nil {
-			return nil, fmt.Errorf("Unable to get interface addrs for %s: %v", iface.Name, err)
+			return nil, errors.Wrapf(err, "Unable to get interface addrs for %s", iface.Name)
 		}
 
 		for _, addr := range addrs {
@@ -92,7 +93,7 @@ func _getHighestIP(ifs []net.Interface) (net.IP, error) {
 func getLoopbackIP() (net.IP, error) {
 	iface, err := net.InterfaceByName("lo")
 	if err != nil {
-		return nil, fmt.Errorf("Unable to get interface lo: %v", err)
+		return nil, errors.Wrap(err, "Unable to get interface lo")
 	}
 
 	return _getLoopbackIP(iface)
@@ -101,7 +102,7 @@ func getLoopbackIP() (net.IP, error) {
 func _getLoopbackIP(iface *net.Interface) (net.IP, error) {
 	addrs, err := iface.Addrs()
 	if err != nil {
-		return nil, fmt.Errorf("Unable to get interface addresses: %v", err)
+		return nil, errors.Wrap(err, "Unable to get interface addresses")
 	}
 
 	candidates := make([]net.IP, 0)
diff --git a/net/prefix.go b/net/prefix.go
index d2287bdd..9e121de7 100644
--- a/net/prefix.go
+++ b/net/prefix.go
@@ -8,6 +8,7 @@ import (
 	"strings"
 
 	"github.com/bio-routing/bio-rd/net/api"
+	"github.com/pkg/errors"
 )
 
 // Prefix represents an IPv4 prefix
@@ -62,7 +63,7 @@ func StrToAddr(x string) (uint32, error) {
 	for i := 0; i < 4; i++ {
 		y, err := strconv.Atoi(parts[i])
 		if err != nil {
-			return 0, fmt.Errorf("Unable to convert %q to int: %v", parts[i], err)
+			return 0, errors.Wrapf(err, "Unable to convert %q to int", parts[i])
 		}
 
 		if y > 255 {
diff --git a/protocols/bgp/packet/decoder.go b/protocols/bgp/packet/decoder.go
index 5ad26c87..f002d31f 100644
--- a/protocols/bgp/packet/decoder.go
+++ b/protocols/bgp/packet/decoder.go
@@ -6,6 +6,7 @@ import (
 	"net"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -13,12 +14,12 @@ import (
 func Decode(buf *bytes.Buffer, opt *DecodeOptions) (*BGPMessage, error) {
 	hdr, err := decodeHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Failed to decode header: %v", err)
+		return nil, errors.Wrap(err, "Failed to decode header")
 	}
 
 	body, err := decodeMsgBody(buf, hdr.Type, hdr.Length-MinLen, opt)
 	if err != nil {
-		return nil, fmt.Errorf("Failed to decode message: %v", err)
+		return nil, errors.Wrap(err, "Failed to decode message")
 	}
 
 	return &BGPMessage{
@@ -132,7 +133,7 @@ func invalidErrCode(n *BGPNotification) (*BGPNotification, error) {
 func DecodeOpenMsg(buf *bytes.Buffer) (*BGPOpen, error) {
 	msg, err := _decodeOpenMsg(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode OPEN message: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode OPEN message")
 	}
 	return msg.(*BGPOpen), err
 }
@@ -160,7 +161,7 @@ func _decodeOpenMsg(buf *bytes.Buffer) (interface{}, error) {
 
 	msg.OptParams, err = decodeOptParams(buf, msg.OptParmLen)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode optional parameters: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode optional parameters")
 	}
 
 	return msg, nil
@@ -187,7 +188,7 @@ func decodeOptParams(buf *bytes.Buffer, optParmLen uint8) ([]OptParam, error) {
 		case CapabilitiesParamType:
 			caps, err := decodeCapabilities(buf, o.Length)
 			if err != nil {
-				return nil, fmt.Errorf("Unable to decode capabilities: %v", err)
+				return nil, errors.Wrap(err, "Unable to decode capabilities")
 			}
 
 			o.Value = caps
@@ -210,7 +211,7 @@ func decodeCapabilities(buf *bytes.Buffer, length uint8) (Capabilities, error) {
 	for read < length {
 		cap, err := decodeCapability(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode capability: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode capability")
 		}
 
 		ret = append(ret, cap)
@@ -242,20 +243,20 @@ func decodeCapability(buf *bytes.Buffer) (Capability, error) {
 	case AddPathCapabilityCode:
 		addPathCap, err := decodeAddPathCapability(buf)
 		if err != nil {
-			return cap, fmt.Errorf("Unable to decode add path capability: %v", err)
+			return cap, errors.Wrap(err, "Unable to decode add path capability")
 		}
 		cap.Value = addPathCap
 	case ASN4CapabilityCode:
 		asn4Cap, err := decodeASN4Capability(buf)
 		if err != nil {
-			return cap, fmt.Errorf("Unable to decode 4 octet ASN capability: %v", err)
+			return cap, errors.Wrap(err, "Unable to decode 4 octet ASN capability")
 		}
 		cap.Value = asn4Cap
 	default:
 		for i := uint8(0); i < cap.Length; i++ {
 			_, err := buf.ReadByte()
 			if err != nil {
-				return cap, fmt.Errorf("Read failed: %v", err)
+				return cap, errors.Wrap(err, "Read failed")
 			}
 		}
 	}
diff --git a/protocols/bgp/packet/mp_reach_nlri.go b/protocols/bgp/packet/mp_reach_nlri.go
index b714dc19..350c0909 100644
--- a/protocols/bgp/packet/mp_reach_nlri.go
+++ b/protocols/bgp/packet/mp_reach_nlri.go
@@ -6,6 +6,7 @@ import (
 
 	bnet "github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -65,7 +66,7 @@ func deserializeMultiProtocolReachNLRI(b []byte, addPath bool) (MultiProtocolRea
 
 	n.NextHop, err = bnet.IPFromBytes(variable[:nextHopLength])
 	if err != nil {
-		return MultiProtocolReachNLRI{}, fmt.Errorf("Failed to decode next hop IP: %v", err)
+		return MultiProtocolReachNLRI{}, errors.Wrap(err, "Failed to decode next hop IP")
 	}
 	budget -= int(nextHopLength)
 
diff --git a/protocols/bgp/packet/nlri.go b/protocols/bgp/packet/nlri.go
index 1f4f7f6e..babb026d 100644
--- a/protocols/bgp/packet/nlri.go
+++ b/protocols/bgp/packet/nlri.go
@@ -7,6 +7,7 @@ import (
 
 	bnet "github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -32,7 +33,7 @@ func decodeNLRIs(buf *bytes.Buffer, length uint16, afi uint16, addPath bool) (*N
 	for p < length {
 		nlri, consumed, err = decodeNLRI(buf, afi, addPath)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode NLRI: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode NLRI")
 		}
 		p += uint16(consumed)
 
@@ -59,7 +60,7 @@ func decodeNLRI(buf *bytes.Buffer, afi uint16, addPath bool) (*NLRI, uint8, erro
 			&nlri.PathIdentifier,
 		})
 		if err != nil {
-			return nil, consumed, fmt.Errorf("Unable to decode path identifier: %v", err)
+			return nil, consumed, errors.Wrap(err, "Unable to decode path identifier")
 		}
 
 		consumed += pathIdentifierLen
diff --git a/protocols/bgp/packet/path_attributes.go b/protocols/bgp/packet/path_attributes.go
index a09a3e2c..6c312fdd 100644
--- a/protocols/bgp/packet/path_attributes.go
+++ b/protocols/bgp/packet/path_attributes.go
@@ -9,6 +9,7 @@ import (
 	"github.com/bio-routing/bio-rd/protocols/bgp/types"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -23,7 +24,7 @@ func decodePathAttrs(buf *bytes.Buffer, tpal uint16, opt *DecodeOptions) (*PathA
 	for p < tpal {
 		pa, consumed, err = decodePathAttr(buf, opt)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode path attr: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode path attr")
 		}
 		p += consumed
 
@@ -44,7 +45,7 @@ func decodePathAttr(buf *bytes.Buffer, opt *DecodeOptions) (pa *PathAttribute, c
 
 	err = decodePathAttrFlags(buf, pa)
 	if err != nil {
-		return nil, consumed, fmt.Errorf("Unable to get path attribute flags: %v", err)
+		return nil, consumed, errors.Wrap(err, "Unable to get path attribute flags")
 	}
 	consumed++
 
@@ -63,7 +64,7 @@ func decodePathAttr(buf *bytes.Buffer, opt *DecodeOptions) (pa *PathAttribute, c
 	switch pa.TypeCode {
 	case OriginAttr:
 		if err := pa.decodeOrigin(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode Origin: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode Origin")
 		}
 	case ASPathAttr:
 		asnLength := uint8(2)
@@ -72,62 +73,62 @@ func decodePathAttr(buf *bytes.Buffer, opt *DecodeOptions) (pa *PathAttribute, c
 		}
 
 		if err := pa.decodeASPath(buf, asnLength); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode AS Path: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode AS Path")
 		}
 	/* Don't decodeAS4Paths yet: The rest of the software does not support it right yet!
 	case AS4PathAttr:
 		if err := pa.decodeASPath(buf, 4); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode AS4 Path: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode AS4 Path")
 		}*/
 	case NextHopAttr:
 		if err := pa.decodeNextHop(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode Next-Hop: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode Next-Hop")
 		}
 	case MEDAttr:
 		if err := pa.decodeMED(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode MED: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode MED")
 		}
 	case LocalPrefAttr:
 		if err := pa.decodeLocalPref(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode local pref: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode local pref")
 		}
 	case AggregatorAttr:
 		if err := pa.decodeAggregator(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode Aggregator: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode Aggregator")
 		}
 	case AtomicAggrAttr:
 		// Nothing to do for 0 octet long attribute
 	case CommunitiesAttr:
 		if err := pa.decodeCommunities(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode Community: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode Community")
 		}
 	case OriginatorIDAttr:
 		if err := pa.decodeOriginatorID(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode OriginatorID: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode OriginatorID")
 		}
 	case ClusterListAttr:
 		if err := pa.decodeClusterList(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode OriginatorID: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode OriginatorID")
 		}
 	case MultiProtocolReachNLRICode:
 		if err := pa.decodeMultiProtocolReachNLRI(buf, opt.AddPath); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to multi protocol reachable NLRI: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to multi protocol reachable NLRI")
 		}
 	case MultiProtocolUnreachNLRICode:
 		if err := pa.decodeMultiProtocolUnreachNLRI(buf, opt.AddPath); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to multi protocol unreachable NLRI: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to multi protocol unreachable NLRI")
 		}
 	case AS4AggregatorAttr:
 		if err := pa.decodeAS4Aggregator(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to skip not supported AS4Aggregator: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to skip not supported AS4Aggregator")
 		}
 	case LargeCommunitiesAttr:
 		if err := pa.decodeLargeCommunities(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode large communities: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode large communities")
 		}
 	default:
 		if err := pa.decodeUnknown(buf); err != nil {
-			return nil, consumed, fmt.Errorf("Failed to decode unknown attribute: %v", err)
+			return nil, consumed, errors.Wrap(err, "Failed to decode unknown attribute")
 		}
 	}
 
@@ -138,7 +139,7 @@ func (pa *PathAttribute) decodeMultiProtocolReachNLRI(buf *bytes.Buffer, addPath
 	b := make([]byte, pa.Length)
 	n, err := buf.Read(b)
 	if err != nil {
-		return fmt.Errorf("Unable to read %d bytes from buffer: %v", pa.Length, err)
+		return errors.Wrapf(err, "Unable to read %d bytes from buffer", pa.Length)
 	}
 	if n != int(pa.Length) {
 		return fmt.Errorf("Unable to read %d bytes from buffer, only got %d bytes", pa.Length, n)
@@ -146,7 +147,7 @@ func (pa *PathAttribute) decodeMultiProtocolReachNLRI(buf *bytes.Buffer, addPath
 
 	nlri, err := deserializeMultiProtocolReachNLRI(b, addPath)
 	if err != nil {
-		return fmt.Errorf("Unable to decode MP_REACH_NLRI: %v", err)
+		return errors.Wrap(err, "Unable to decode MP_REACH_NLRI")
 	}
 
 	pa.Value = nlri
@@ -157,7 +158,7 @@ func (pa *PathAttribute) decodeMultiProtocolUnreachNLRI(buf *bytes.Buffer, addPa
 	b := make([]byte, pa.Length)
 	n, err := buf.Read(b)
 	if err != nil {
-		return fmt.Errorf("Unable to read %d bytes from buffer: %v", pa.Length, err)
+		return errors.Wrapf(err, "Unable to read %d bytes from buffer", pa.Length)
 	}
 	if n != int(pa.Length) {
 		return fmt.Errorf("Unable to read %d bytes from buffer, only got %d bytes", pa.Length, n)
@@ -165,7 +166,7 @@ func (pa *PathAttribute) decodeMultiProtocolUnreachNLRI(buf *bytes.Buffer, addPa
 
 	nlri, err := deserializeMultiProtocolUnreachNLRI(b, addPath)
 	if err != nil {
-		return fmt.Errorf("Unable to decode MP_UNREACH_NLRI: %v", err)
+		return errors.Wrap(err, "Unable to decode MP_UNREACH_NLRI")
 	}
 
 	pa.Value = nlri
@@ -177,7 +178,7 @@ func (pa *PathAttribute) decodeUnknown(buf *bytes.Buffer) error {
 
 	err := decode.Decode(buf, []interface{}{&u})
 	if err != nil {
-		return fmt.Errorf("Unable to decode: %v", err)
+		return errors.Wrap(err, "Unable to decode")
 	}
 
 	pa.Value = u
@@ -190,7 +191,7 @@ func (pa *PathAttribute) decodeOrigin(buf *bytes.Buffer) error {
 	p := uint16(0)
 	err := decode.Decode(buf, []interface{}{&origin})
 	if err != nil {
-		return fmt.Errorf("Unable to decode: %v", err)
+		return errors.Wrap(err, "Unable to decode")
 	}
 
 	pa.Value = origin
@@ -269,7 +270,7 @@ func (pa *PathAttribute) decodeNextHop(buf *bytes.Buffer) error {
 	nextHop := uint32(0)
 	err := decode.Decode(buf, []interface{}{&nextHop})
 	if err != nil {
-		return fmt.Errorf("Unable to decode next hop: %v", err)
+		return errors.Wrap(err, "Unable to decode next hop")
 	}
 
 	pa.Value = bnet.IPv4(nextHop)
@@ -360,7 +361,7 @@ func (pa *PathAttribute) decodeAS4Aggregator(buf *bytes.Buffer) error {
 func (pa *PathAttribute) decodeUint32(buf *bytes.Buffer, attrName string) error {
 	v, err := read4BytesAsUint32(buf)
 	if err != nil {
-		return fmt.Errorf("Unable to decode %s: %v", attrName, err)
+		return errors.Wrapf(err, "Unable to decode %s", attrName)
 	}
 
 	pa.Value = v
@@ -368,7 +369,7 @@ func (pa *PathAttribute) decodeUint32(buf *bytes.Buffer, attrName string) error
 	p := uint16(4)
 	err = dumpNBytes(buf, pa.Length-p)
 	if err != nil {
-		return fmt.Errorf("dumpNBytes failed: %v", err)
+		return errors.Wrap(err, "dumpNBytes failed")
 	}
 
 	return nil
diff --git a/protocols/bgp/server/bmp_router.go b/protocols/bgp/server/bmp_router.go
index 84f5c668..ff01369b 100644
--- a/protocols/bgp/server/bmp_router.go
+++ b/protocols/bgp/server/bmp_router.go
@@ -13,6 +13,7 @@ import (
 	"github.com/bio-routing/bio-rd/routingtable"
 	"github.com/bio-routing/bio-rd/routingtable/filter"
 	"github.com/bio-routing/bio-rd/routingtable/locRIB"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/taktv6/tflow2/convert"
 )
@@ -280,7 +281,7 @@ func (r *router) processPeerUpNotification(msg *bmppkt.PeerUpNotification) error
 
 	sentOpen, err := packet.DecodeOpenMsg(bytes.NewBuffer(msg.SentOpenMsg[packet.HeaderLen:]))
 	if err != nil {
-		return fmt.Errorf("Unable to decode sent open message sent from %v to %v: %v", r.address.String(), msg.PerPeerHeader.PeerAddress, err)
+		return errors.Wrapf(err, "Unable to decode sent open message sent from %v to %v", r.address.String(), msg.PerPeerHeader.PeerAddress)
 	}
 
 	if len(msg.ReceivedOpenMsg) < packet.MinOpenLen {
@@ -289,7 +290,7 @@ func (r *router) processPeerUpNotification(msg *bmppkt.PeerUpNotification) error
 
 	recvOpen, err := packet.DecodeOpenMsg(bytes.NewBuffer(msg.ReceivedOpenMsg[packet.HeaderLen:]))
 	if err != nil {
-		return fmt.Errorf("Unable to decode received open message sent from %v to %v: %v", msg.PerPeerHeader.PeerAddress, r.address.String(), err)
+		return errors.Wrapf(err, "Unable to decode received open message sent from %v to %v", msg.PerPeerHeader.PeerAddress, r.address.String())
 	}
 
 	addrLen := net.IPv4len
diff --git a/protocols/bgp/server/bmp_server.go b/protocols/bgp/server/bmp_server.go
index d49355ee..30916c3c 100644
--- a/protocols/bgp/server/bmp_server.go
+++ b/protocols/bgp/server/bmp_server.go
@@ -10,6 +10,7 @@ import (
 	bmppkt "github.com/bio-routing/bio-rd/protocols/bmp/packet"
 	"github.com/bio-routing/bio-rd/routingtable"
 	"github.com/bio-routing/bio-rd/routingtable/locRIB"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/taktv6/tflow2/convert"
 )
@@ -132,7 +133,7 @@ func recvBMPMsg(c net.Conn) (msg []byte, err error) {
 	buffer := make([]byte, defaultBufferLen)
 	_, err = io.ReadFull(c, buffer[0:bmppkt.MinLen])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	l := convert.Uint32b(buffer[1:5])
@@ -145,7 +146,7 @@ func recvBMPMsg(c net.Conn) (msg []byte, err error) {
 	toRead := l
 	_, err = io.ReadFull(c, buffer[bmppkt.MinLen:toRead])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	return buffer[0:toRead], nil
diff --git a/protocols/bgp/server/fsm.go b/protocols/bgp/server/fsm.go
index 6e11d667..2d1d3ce0 100644
--- a/protocols/bgp/server/fsm.go
+++ b/protocols/bgp/server/fsm.go
@@ -9,6 +9,7 @@ import (
 	"time"
 
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -267,7 +268,7 @@ func (fsm *FSM) sendOpen() error {
 
 	_, err := fsm.con.Write(msg)
 	if err != nil {
-		return fmt.Errorf("Unable to send OPEN message: %v", err)
+		return errors.Wrap(err, "Unable to send OPEN message")
 	}
 
 	return nil
@@ -296,7 +297,7 @@ func (fsm *FSM) sendNotification(errorCode uint8, errorSubCode uint8) error {
 
 	_, err := fsm.con.Write(msg)
 	if err != nil {
-		return fmt.Errorf("Unable to send NOTIFICATION message: %v", err)
+		return errors.Wrap(err, "Unable to send NOTIFICATION message")
 	}
 
 	return nil
@@ -307,7 +308,7 @@ func (fsm *FSM) sendKeepalive() error {
 
 	_, err := fsm.con.Write(msg)
 	if err != nil {
-		return fmt.Errorf("Unable to send KEEPALIVE message: %v", err)
+		return errors.Wrap(err, "Unable to send KEEPALIVE message")
 	}
 
 	return nil
@@ -317,14 +318,14 @@ func recvMsg(c net.Conn) (msg []byte, err error) {
 	buffer := make([]byte, packet.MaxLen)
 	_, err = io.ReadFull(c, buffer[0:packet.MinLen])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	l := int(buffer[16])*256 + int(buffer[17])
 	toRead := l
 	_, err = io.ReadFull(c, buffer[packet.MinLen:toRead])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	return buffer, nil
diff --git a/protocols/bgp/server/fsm_established.go b/protocols/bgp/server/fsm_established.go
index 05e540b5..5ea39ba2 100644
--- a/protocols/bgp/server/fsm_established.go
+++ b/protocols/bgp/server/fsm_established.go
@@ -9,6 +9,7 @@ import (
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -58,11 +59,11 @@ func (s establishedState) run() (state, string) {
 func (s *establishedState) init() error {
 	host, _, err := net.SplitHostPort(s.fsm.con.LocalAddr().String())
 	if err != nil {
-		return fmt.Errorf("Unable to get local address: %v", err)
+		return errors.Wrap(err, "Unable to get local address")
 	}
 	localAddr, err := bnet.IPFromString(host)
 	if err != nil {
-		return fmt.Errorf("Unable to parse address: %v", err)
+		return errors.Wrap(err, "Unable to parse address")
 	}
 
 	n := &routingtable.Neighbor{
diff --git a/protocols/bgp/server/server.go b/protocols/bgp/server/server.go
index 76d8ee24..fe8558ef 100644
--- a/protocols/bgp/server/server.go
+++ b/protocols/bgp/server/server.go
@@ -1,12 +1,12 @@
 package server
 
 import (
-	"fmt"
 	"net"
 	"strings"
 	"sync"
 
 	"github.com/bio-routing/bio-rd/config"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -38,7 +38,7 @@ func (b *bgpServer) RouterID() uint32 {
 
 func (b *bgpServer) Start(c *config.Global) error {
 	if err := c.SetDefaultGlobalConfigValues(); err != nil {
-		return fmt.Errorf("Failed to load defaults: %v", err)
+		return errors.Wrap(err, "Failed to load defaults")
 	}
 
 	log.Infof("ROUTER ID: %d\n", c.RouterID)
@@ -50,7 +50,7 @@ func (b *bgpServer) Start(c *config.Global) error {
 		for _, addr := range c.LocalAddressList {
 			l, err := NewTCPListener(addr, c.Port, acceptCh)
 			if err != nil {
-				return fmt.Errorf("Failed to start TCPListener for %s: %v", addr.String(), err)
+				return errors.Wrapf(err, "Failed to start TCPListener for %s", addr.String())
 			}
 			b.listeners = append(b.listeners, l)
 		}
diff --git a/protocols/bgp/server/update_helper.go b/protocols/bgp/server/update_helper.go
index a510e54e..f8822dec 100644
--- a/protocols/bgp/server/update_helper.go
+++ b/protocols/bgp/server/update_helper.go
@@ -1,10 +1,10 @@
 package server
 
 import (
-	"fmt"
 	"io"
 
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
+	"github.com/pkg/errors"
 
 	log "github.com/sirupsen/logrus"
 )
@@ -18,7 +18,7 @@ func serializeAndSendUpdate(out io.Writer, update serializeAbleUpdate, opt *pack
 
 	_, err = out.Write(updateBytes)
 	if err != nil {
-		return fmt.Errorf("Failed sending Update: %v", err)
+		return errors.Wrap(err, "Failed sending Update")
 	}
 	return nil
 }
diff --git a/protocols/bgp/server/update_helper_test.go b/protocols/bgp/server/update_helper_test.go
index fee9d895..3b8ec458 100644
--- a/protocols/bgp/server/update_helper_test.go
+++ b/protocols/bgp/server/update_helper_test.go
@@ -2,12 +2,12 @@ package server
 
 import (
 	"bytes"
-	"errors"
 	"io"
 	"testing"
 
 	bnet "github.com/bio-routing/bio-rd/net"
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
+	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -89,7 +89,12 @@ func TestSerializeAndSendUpdate(t *testing.T) {
 		t.Run(test.name, func(t *testing.T) {
 			opt := &packet.EncodeOptions{}
 			err := serializeAndSendUpdate(test.buf, test.testUpdate, opt)
-			assert.Equal(t, test.err, err)
+
+			if test.err == nil {
+				assert.NoError(t, err)
+			} else {
+				assert.Equal(t, test.err.Error(), err.Error())
+			}
 
 			assert.Equal(t, test.expected, test.buf.Bytes())
 		})
diff --git a/protocols/bmp/packet/decode.go b/protocols/bmp/packet/decode.go
index a76f6b78..4d97389a 100644
--- a/protocols/bmp/packet/decode.go
+++ b/protocols/bmp/packet/decode.go
@@ -3,6 +3,8 @@ package packet
 import (
 	"bytes"
 	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 const (
@@ -38,7 +40,7 @@ func Decode(msg []byte) (Msg, error) {
 
 	ch, err := decodeCommonHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode common header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode common header")
 	}
 
 	if ch.Version != BMPVersion {
@@ -49,49 +51,49 @@ func Decode(msg []byte) (Msg, error) {
 	case RouteMonitoringType:
 		rm, err := decodeRouteMonitoringMsg(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode route monitoring message: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode route monitoring message")
 		}
 
 		return rm, err
 	case StatisticsReportType:
 		sr, err := decodeStatsReport(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode stats report: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode stats report")
 		}
 
 		return sr, nil
 	case PeerDownNotificationType:
 		pd, err := decodePeerDownNotification(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode peer down notification: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode peer down notification")
 		}
 
 		return pd, nil
 	case PeerUpNotificationType:
 		pu, err := decodePeerUpNotification(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode peer up notification: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode peer up notification")
 		}
 
 		return pu, nil
 	case InitiationMessageType:
 		im, err := decodeInitiationMessage(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode initiation message: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode initiation message")
 		}
 
 		return im, nil
 	case TerminationMessageType:
 		tm, err := decodeTerminationMessage(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode termination message: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode termination message")
 		}
 
 		return tm, nil
 	case RouteMirroringMessageType:
 		rm, err := decodeRouteMirroringMsg(buf, ch)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode route mirroring message: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode route mirroring message")
 		}
 
 		return rm, nil
diff --git a/protocols/bmp/packet/initiation_message.go b/protocols/bmp/packet/initiation_message.go
index 6fbc3f30..896599d5 100644
--- a/protocols/bmp/packet/initiation_message.go
+++ b/protocols/bmp/packet/initiation_message.go
@@ -2,7 +2,8 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // InitiationMessage represents an initiation message
@@ -28,7 +29,7 @@ func decodeInitiationMessage(buf *bytes.Buffer, ch *CommonHeader) (Msg, error) {
 	for read < toRead {
 		tlv, err := decodeInformationTLV(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode TLV: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode TLV")
 		}
 
 		im.TLVs = append(im.TLVs, tlv)
diff --git a/protocols/bmp/packet/peer_down.go b/protocols/bmp/packet/peer_down.go
index 7b030304..c81d46f9 100644
--- a/protocols/bmp/packet/peer_down.go
+++ b/protocols/bmp/packet/peer_down.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decoder"
+	"github.com/pkg/errors"
 )
 
 const (
@@ -32,7 +32,7 @@ func decodePeerDownNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerDownN
 
 	pph, err := decodePerPeerHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode per peer header")
 	}
 
 	p.PerPeerHeader = pph
@@ -57,7 +57,7 @@ func decodePeerDownNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerDownN
 
 	err = decoder.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read Data: %v", err)
+		return nil, errors.Wrap(err, "Unable to read Data")
 	}
 
 	return p, nil
diff --git a/protocols/bmp/packet/peer_up.go b/protocols/bmp/packet/peer_up.go
index 34d37a7c..c0e44337 100644
--- a/protocols/bmp/packet/peer_up.go
+++ b/protocols/bmp/packet/peer_up.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decoder"
+	"github.com/pkg/errors"
 )
 
 const (
@@ -36,7 +36,7 @@ func decodePeerUpNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerUpNotif
 
 	pph, err := decodePerPeerHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode per peer header")
 	}
 
 	p.PerPeerHeader = pph
@@ -54,13 +54,13 @@ func decodePeerUpNotification(buf *bytes.Buffer, ch *CommonHeader) (*PeerUpNotif
 
 	sentOpenMsg, err := getOpenMsg(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to get OPEN message: %v", err)
+		return nil, errors.Wrap(err, "Unable to get OPEN message")
 	}
 	p.SentOpenMsg = sentOpenMsg
 
 	recvOpenMsg, err := getOpenMsg(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to get OPEN message: %v", err)
+		return nil, errors.Wrap(err, "Unable to get OPEN message")
 	}
 	p.ReceivedOpenMsg = recvOpenMsg
 
@@ -87,7 +87,7 @@ func getOpenMsg(buf *bytes.Buffer) ([]byte, error) {
 	}
 	err := decoder.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read: %v", err)
+		return nil, errors.Wrap(err, "Unable to read")
 	}
 
 	if msg[OpenMsgMinLen-1] == 0 {
@@ -101,7 +101,7 @@ func getOpenMsg(buf *bytes.Buffer) ([]byte, error) {
 
 	err = decoder.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read: %v", err)
+		return nil, errors.Wrap(err, "Unable to read")
 	}
 
 	msg = append(msg, optParams...)
diff --git a/protocols/bmp/packet/route_mirroring.go b/protocols/bmp/packet/route_mirroring.go
index e3d013a0..9ad2fe49 100644
--- a/protocols/bmp/packet/route_mirroring.go
+++ b/protocols/bmp/packet/route_mirroring.go
@@ -2,7 +2,8 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // RouteMirroringMsg represents a route mirroring message
@@ -24,7 +25,7 @@ func decodeRouteMirroringMsg(buf *bytes.Buffer, ch *CommonHeader) (*RouteMirrori
 
 	pph, err := decodePerPeerHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode per peer header")
 	}
 
 	rm.PerPeerHeader = pph
@@ -35,7 +36,7 @@ func decodeRouteMirroringMsg(buf *bytes.Buffer, ch *CommonHeader) (*RouteMirrori
 	for read < toRead {
 		tlv, err := decodeInformationTLV(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode TLV: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode TLV")
 		}
 
 		rm.TLVs = append(rm.TLVs, tlv)
diff --git a/protocols/bmp/packet/route_monitoring.go b/protocols/bmp/packet/route_monitoring.go
index d76aa453..8f69c64c 100644
--- a/protocols/bmp/packet/route_monitoring.go
+++ b/protocols/bmp/packet/route_monitoring.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decoder"
+	"github.com/pkg/errors"
 )
 
 // RouteMonitoringMsg represents a Route Monitoring Message
@@ -26,7 +26,7 @@ func decodeRouteMonitoringMsg(buf *bytes.Buffer, ch *CommonHeader) (*RouteMonito
 
 	pph, err := decodePerPeerHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode per peer header")
 	}
 
 	rm.PerPeerHeader = pph
diff --git a/protocols/bmp/packet/stats_report.go b/protocols/bmp/packet/stats_report.go
index 3fa53995..f9a9709c 100644
--- a/protocols/bmp/packet/stats_report.go
+++ b/protocols/bmp/packet/stats_report.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decoder"
+	"github.com/pkg/errors"
 )
 
 // StatsReport represents a stats report message
@@ -27,7 +27,7 @@ func decodeStatsReport(buf *bytes.Buffer, ch *CommonHeader) (Msg, error) {
 
 	pph, err := decodePerPeerHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode per peer header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode per peer header")
 	}
 
 	sr.PerPeerHeader = pph
@@ -45,7 +45,7 @@ func decodeStatsReport(buf *bytes.Buffer, ch *CommonHeader) (Msg, error) {
 	for i := uint32(0); i < sr.StatsCount; i++ {
 		infoTLV, err := decodeInformationTLV(buf)
 		if err != nil {
-			return sr, fmt.Errorf("Unable to decode information TLV: %v", err)
+			return sr, errors.Wrap(err, "Unable to decode information TLV")
 		}
 
 		sr.Stats[i] = infoTLV
diff --git a/protocols/bmp/packet/termination_message.go b/protocols/bmp/packet/termination_message.go
index 8021fbeb..e4ff9835 100644
--- a/protocols/bmp/packet/termination_message.go
+++ b/protocols/bmp/packet/termination_message.go
@@ -2,7 +2,8 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // TerminationMessage represents a termination message
@@ -28,7 +29,7 @@ func decodeTerminationMessage(buf *bytes.Buffer, ch *CommonHeader) (*Termination
 	for read < toRead {
 		tlv, err := decodeInformationTLV(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode TLV: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode TLV")
 		}
 
 		tm.TLVs = append(tm.TLVs, tlv)
diff --git a/protocols/bmp/server/server.go b/protocols/bmp/server/server.go
index 2415929a..50cccf15 100644
--- a/protocols/bmp/server/server.go
+++ b/protocols/bmp/server/server.go
@@ -9,6 +9,7 @@ import (
 
 	"github.com/bio-routing/bio-rd/protocols/bgp/packet"
 	"github.com/bio-routing/bio-rd/routingtable/locRIB"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/taktv6/tflow2/convert"
 )
@@ -70,7 +71,7 @@ func recvMsg(c net.Conn) (msg []byte, err error) {
 	buffer := make([]byte, defaultBufferLen)
 	_, err = io.ReadFull(c, buffer[0:packet.MinLen])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	l := convert.Uint32b(buffer[1:3])
@@ -83,7 +84,7 @@ func recvMsg(c net.Conn) (msg []byte, err error) {
 	toRead := l
 	_, err = io.ReadFull(c, buffer[packet.MinLen:toRead])
 	if err != nil {
-		return nil, fmt.Errorf("Read failed: %v", err)
+		return nil, errors.Wrap(err, "Read failed")
 	}
 
 	return buffer, nil
diff --git a/protocols/device/server.go b/protocols/device/server.go
index 22eeb29d..00e29266 100644
--- a/protocols/device/server.go
+++ b/protocols/device/server.go
@@ -1,8 +1,9 @@
 package device
 
 import (
-	"fmt"
 	"sync"
+
+	"github.com/pkg/errors"
 )
 
 // Server represents a device server
@@ -29,7 +30,7 @@ func New() (*Server, error) {
 	srv := newWithAdapter(nil)
 	err := srv.loadAdapter()
 	if err != nil {
-		return nil, fmt.Errorf("Unable to create OS adapter: %v", err)
+		return nil, errors.Wrap(err, "Unable to create OS adapter")
 	}
 
 	return srv, nil
@@ -48,7 +49,7 @@ func newWithAdapter(a osAdapter) *Server {
 func (ds *Server) Start() error {
 	err := ds.osAdapter.start()
 	if err != nil {
-		return fmt.Errorf("Unable to start osAdapter: %v", err)
+		return errors.Wrap(err, "Unable to start osAdapter")
 	}
 
 	return nil
diff --git a/protocols/device/server_linux.go b/protocols/device/server_linux.go
index fa344d81..31bc93fa 100644
--- a/protocols/device/server_linux.go
+++ b/protocols/device/server_linux.go
@@ -1,9 +1,8 @@
 package device
 
 import (
-	"fmt"
-
 	bnet "github.com/bio-routing/bio-rd/net"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/vishvananda/netlink"
 )
@@ -11,7 +10,7 @@ import (
 func (ds *Server) loadAdapter() error {
 	a, err := newOSAdapterLinux(ds)
 	if err != nil {
-		return fmt.Errorf("Unable to create linux adapter: %v", err)
+		return errors.Wrap(err, "Unable to create linux adapter")
 	}
 
 	ds.osAdapter = a
@@ -31,7 +30,7 @@ func newOSAdapterLinux(srv *Server) (*osAdapterLinux, error) {
 
 	h, err := netlink.NewHandle()
 	if err != nil {
-		return nil, fmt.Errorf("Failed to create netlink handle: %v", err)
+		return nil, errors.Wrap(err, "Failed to create netlink handle")
 	}
 
 	o.handle = h
@@ -42,18 +41,18 @@ func (o *osAdapterLinux) start() error {
 	chLU := make(chan netlink.LinkUpdate)
 	err := netlink.LinkSubscribe(chLU, o.done)
 	if err != nil {
-		return fmt.Errorf("Unable to subscribe for link updates: %v", err)
+		return errors.Wrap(err, "Unable to subscribe for link updates")
 	}
 
 	chAU := make(chan netlink.AddrUpdate)
 	err = netlink.AddrSubscribe(chAU, o.done)
 	if err != nil {
-		return fmt.Errorf("Unable to subscribe for address updates: %v", err)
+		return errors.Wrap(err, "Unable to subscribe for address updates")
 	}
 
 	err = o.init()
 	if err != nil {
-		return fmt.Errorf("Init failed: %v", err)
+		return errors.Wrap(err, "Init failed")
 	}
 
 	go o.monitorLinks(chLU)
@@ -65,7 +64,7 @@ func (o *osAdapterLinux) start() error {
 func (o *osAdapterLinux) init() error {
 	links, err := o.handle.LinkList()
 	if err != nil {
-		return fmt.Errorf("Unable to get links: %v", err)
+		return errors.Wrap(err, "Unable to get links")
 	}
 
 	for _, l := range links {
@@ -74,7 +73,7 @@ func (o *osAdapterLinux) init() error {
 		for _, f := range []int{4, 6} {
 			addrs, err := o.handle.AddrList(l, f)
 			if err != nil {
-				return fmt.Errorf("Unable to get addresses for interface %s: %v", d.Name, err)
+				return errors.Wrapf(err, "Unable to get addresses for interface %s", d.Name)
 			}
 
 			for _, addr := range addrs {
diff --git a/protocols/isis/packet/csnp.go b/protocols/isis/packet/csnp.go
index c528a8fb..ae6eaf73 100644
--- a/protocols/isis/packet/csnp.go
+++ b/protocols/isis/packet/csnp.go
@@ -2,13 +2,13 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 	"math"
 	"sort"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
 	umath "github.com/bio-routing/bio-rd/util/math"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -133,7 +133,7 @@ func DecodeCSNP(buf *bytes.Buffer) (*CSNP, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	nEntries := (csnp.PDULength - CSNPMinLen) / LSPEntryLen
@@ -141,7 +141,7 @@ func DecodeCSNP(buf *bytes.Buffer) (*CSNP, error) {
 	for i := uint16(0); i < nEntries; i++ {
 		lspEntry, err := decodeLSPEntry(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to get LSPEntries: %v", err)
+			return nil, errors.Wrap(err, "Unable to get LSPEntries")
 		}
 		csnp.LSPEntries[i] = *lspEntry
 	}
diff --git a/protocols/isis/packet/header.go b/protocols/isis/packet/header.go
index ca627d2d..8ff00ed2 100644
--- a/protocols/isis/packet/header.go
+++ b/protocols/isis/packet/header.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 )
 
 // ISISHeader represents an ISIS header
@@ -42,7 +42,7 @@ func DecodeHeader(buf *bytes.Buffer) (*ISISHeader, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return h, nil
diff --git a/protocols/isis/packet/hello.go b/protocols/isis/packet/hello.go
index 07dc9dc5..e6170f9b 100644
--- a/protocols/isis/packet/hello.go
+++ b/protocols/isis/packet/hello.go
@@ -2,10 +2,10 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -63,12 +63,12 @@ func DecodeP2PHello(buf *bytes.Buffer) (*P2PHello, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	TLVs, err := readTLVs(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read TLVs: %v", err)
+		return nil, errors.Wrap(err, "Unable to read TLVs")
 	}
 
 	pdu.TLVs = TLVs
@@ -91,12 +91,12 @@ func DecodeL2Hello(buf *bytes.Buffer) (*L2Hello, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	TLVs, err := readTLVs(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read TLVs: %v", err)
+		return nil, errors.Wrap(err, "Unable to read TLVs")
 	}
 
 	pdu.TLVs = TLVs
diff --git a/protocols/isis/packet/isis.go b/protocols/isis/packet/isis.go
index 71aee6cc..d433cd98 100644
--- a/protocols/isis/packet/isis.go
+++ b/protocols/isis/packet/isis.go
@@ -2,7 +2,8 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 const (
@@ -33,7 +34,7 @@ func Decode(buf *bytes.Buffer) (*ISISPacket, error) {
 
 	hdr, err := DecodeHeader(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode header: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode header")
 	}
 	pkt.Header = hdr
 
@@ -41,7 +42,7 @@ func Decode(buf *bytes.Buffer) (*ISISPacket, error) {
 	case P2P_HELLO:
 		p2pHello, err := DecodeP2PHello(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode P2P hello: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode P2P hello")
 		}
 		pkt.Body = p2pHello
 	}
diff --git a/protocols/isis/packet/lsp.go b/protocols/isis/packet/lsp.go
index 0fe4b689..39104ed7 100644
--- a/protocols/isis/packet/lsp.go
+++ b/protocols/isis/packet/lsp.go
@@ -2,11 +2,11 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/FMNSSun/libhash/fletcher"
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -80,12 +80,12 @@ func DecodeLSPDU(buf *bytes.Buffer) (*LSPDU, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	TLVs, err := readTLVs(buf)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read TLVs: %v", err)
+		return nil, errors.Wrap(err, "Unable to read TLVs")
 	}
 
 	pdu.TLVs = TLVs
diff --git a/protocols/isis/packet/lsp_entry.go b/protocols/isis/packet/lsp_entry.go
index 8b4afa55..d9bc599d 100644
--- a/protocols/isis/packet/lsp_entry.go
+++ b/protocols/isis/packet/lsp_entry.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -42,7 +42,7 @@ func decodeLSPEntry(buf *bytes.Buffer) (*LSPEntry, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return lspEntry, nil
diff --git a/protocols/isis/packet/psnp.go b/protocols/isis/packet/psnp.go
index 0686a6b8..82ade828 100644
--- a/protocols/isis/packet/psnp.go
+++ b/protocols/isis/packet/psnp.go
@@ -2,12 +2,12 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 	"math"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
 	umath "github.com/bio-routing/bio-rd/util/math"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -81,7 +81,7 @@ func DecodePSNP(buf *bytes.Buffer) (*PSNP, error) {
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	nEntries := (psnp.PDULength - PSNPMinLen) / LSPEntryLen
@@ -89,7 +89,7 @@ func DecodePSNP(buf *bytes.Buffer) (*PSNP, error) {
 	for i := uint16(0); i < nEntries; i++ {
 		lspEntry, err := decodeLSPEntry(buf)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to get LSPEntries: %v", err)
+			return nil, errors.Wrap(err, "Unable to get LSPEntries")
 		}
 		psnp.LSPEntries[i] = *lspEntry
 	}
diff --git a/protocols/isis/packet/tlv.go b/protocols/isis/packet/tlv.go
index 6fcd8796..72064a48 100644
--- a/protocols/isis/packet/tlv.go
+++ b/protocols/isis/packet/tlv.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 )
 
 // TLV is an interface that all TLVs must fulfill
@@ -42,7 +42,7 @@ func readTLVs(buf *bytes.Buffer) ([]TLV, error) {
 	for read < uint16(length) {
 		err = decode.Decode(buf, headFields)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode fields: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode fields")
 		}
 
 		read += 2
@@ -69,7 +69,7 @@ func readTLVs(buf *bytes.Buffer) ([]TLV, error) {
 		}
 
 		if err != nil {
-			return nil, fmt.Errorf("Unable to read TLV: %v", err)
+			return nil, errors.Wrap(err, "Unable to read TLV")
 		}
 		TLVs = append(TLVs, tlv)
 	}
diff --git a/protocols/isis/packet/tlv_area_addresses.go b/protocols/isis/packet/tlv_area_addresses.go
index 06494998..35ba0d79 100644
--- a/protocols/isis/packet/tlv_area_addresses.go
+++ b/protocols/isis/packet/tlv_area_addresses.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
+	"github.com/pkg/errors"
 )
 
 // AreaAddressesTLVType is the type value of an area address TLV
@@ -29,14 +29,14 @@ func readAreaAddressesTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*A
 	for read < tlvLength {
 		areaLen, err := buf.ReadByte()
 		if err != nil {
-			return nil, fmt.Errorf("Unable to read: %v", err)
+			return nil, errors.Wrap(err, "Unable to read")
 		}
 		read++
 
 		newArea := make(types.AreaID, areaLen)
 		_, err = buf.Read(newArea)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to read: %v", err)
+			return nil, errors.Wrap(err, "Unable to read")
 		}
 		read += areaLen
 
diff --git a/protocols/isis/packet/tlv_checksum.go b/protocols/isis/packet/tlv_checksum.go
index 7adc5e86..05a55f64 100644
--- a/protocols/isis/packet/tlv_checksum.go
+++ b/protocols/isis/packet/tlv_checksum.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -45,7 +45,7 @@ func readChecksumTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*Checks
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_dynamic_hostname.go b/protocols/isis/packet/tlv_dynamic_hostname.go
index 2b5114e9..39a2a80b 100644
--- a/protocols/isis/packet/tlv_dynamic_hostname.go
+++ b/protocols/isis/packet/tlv_dynamic_hostname.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 )
 
 // DynamicHostNameTLVType is the type value of dynamic hostname TLV
@@ -45,7 +45,7 @@ func readDynamicHostnameTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_ip_interface_address.go b/protocols/isis/packet/tlv_ip_interface_address.go
index 012688a8..d34e0051 100644
--- a/protocols/isis/packet/tlv_ip_interface_address.go
+++ b/protocols/isis/packet/tlv_ip_interface_address.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -39,7 +39,7 @@ func readIPInterfaceAddressTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_is_neighbors.go b/protocols/isis/packet/tlv_is_neighbors.go
index 1296fee6..a39db37e 100644
--- a/protocols/isis/packet/tlv_is_neighbors.go
+++ b/protocols/isis/packet/tlv_is_neighbors.go
@@ -2,10 +2,10 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 )
 
 // ISNeighborsTLVType is the type value of an IS Neighbor TLV
@@ -32,7 +32,7 @@ func readISNeighborsTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*ISN
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_p2p_adj_state.go b/protocols/isis/packet/tlv_p2p_adj_state.go
index c4b434ad..ec47038a 100644
--- a/protocols/isis/packet/tlv_p2p_adj_state.go
+++ b/protocols/isis/packet/tlv_p2p_adj_state.go
@@ -2,10 +2,10 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/protocols/isis/types"
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 	"github.com/taktv6/tflow2/convert"
 )
 
@@ -52,7 +52,7 @@ func readP2PAdjacencyStateTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8)
 
 	err := decode.Decode(buf, fields)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to decode fields: %v", err)
+		return nil, errors.Wrap(err, "Unable to decode fields")
 	}
 
 	return pdu, nil
diff --git a/protocols/isis/packet/tlv_protocols_supported.go b/protocols/isis/packet/tlv_protocols_supported.go
index a9597e15..7aafbf95 100644
--- a/protocols/isis/packet/tlv_protocols_supported.go
+++ b/protocols/isis/packet/tlv_protocols_supported.go
@@ -2,9 +2,9 @@ package packet
 
 import (
 	"bytes"
-	"fmt"
 
 	"github.com/bio-routing/bio-rd/util/decode"
+	"github.com/pkg/errors"
 )
 
 // ProtocolsSupportedTLVType is the type value of an protocols supported TLV
@@ -32,7 +32,7 @@ func readProtocolsSupportedTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8
 	for i := uint8(0); i < tlvLength; i++ {
 		err := decode.Decode(buf, fields)
 		if err != nil {
-			return nil, fmt.Errorf("Unable to decode fields: %v", err)
+			return nil, errors.Wrap(err, "Unable to decode fields")
 		}
 		pdu.NetworkLayerProtocolIDs[i] = protoID
 	}
diff --git a/protocols/isis/packet/tlv_unknown.go b/protocols/isis/packet/tlv_unknown.go
index 9488ac1f..08e8ae35 100644
--- a/protocols/isis/packet/tlv_unknown.go
+++ b/protocols/isis/packet/tlv_unknown.go
@@ -3,6 +3,8 @@ package packet
 import (
 	"bytes"
 	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // UnknownTLV represents an unknown TLV
@@ -21,7 +23,7 @@ func readUnknownTLV(buf *bytes.Buffer, tlvType uint8, tlvLength uint8) (*Unknown
 
 	n, err := buf.Read(pdu.TLVValue)
 	if err != nil {
-		return nil, fmt.Errorf("Unable to read: %v", err)
+		return nil, errors.Wrap(err, "Unable to read")
 	}
 
 	if n != int(tlvLength) {
diff --git a/protocols/netlink/netlink_writer.go b/protocols/netlink/netlink_writer.go
index f0fb324b..fae9a1fd 100644
--- a/protocols/netlink/netlink_writer.go
+++ b/protocols/netlink/netlink_writer.go
@@ -9,6 +9,7 @@ import (
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
 	"github.com/bio-routing/bio-rd/routingtable/filter"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 	"github.com/vishvananda/netlink"
 )
@@ -144,7 +145,7 @@ func (nw *NetlinkWriter) addKernel(pfx bnet.Prefix) error {
 	err = netlink.RouteAdd(route)
 	if err != nil {
 		log.Errorf("Error while adding route: %v", err)
-		return fmt.Errorf("Error while adding route: %v", err)
+		return errors.Wrap(err, "Error while adding route")
 	}
 
 	return nil
@@ -163,7 +164,7 @@ func (nw *NetlinkWriter) removeKernel(pfx bnet.Prefix, paths []*route.Path) erro
 
 	err = netlink.RouteDel(route)
 	if err != nil {
-		return fmt.Errorf("Error while removing route: %v", err)
+		return errors.Wrap(err, "Error while removing route")
 	}
 
 	return nil
diff --git a/routingtable/adjRIBOut/adj_rib_out.go b/routingtable/adjRIBOut/adj_rib_out.go
index c9a0bb90..de568f72 100644
--- a/routingtable/adjRIBOut/adj_rib_out.go
+++ b/routingtable/adjRIBOut/adj_rib_out.go
@@ -8,6 +8,7 @@ import (
 	"github.com/bio-routing/bio-rd/route"
 	"github.com/bio-routing/bio-rd/routingtable"
 	"github.com/bio-routing/bio-rd/routingtable/filter"
+	"github.com/pkg/errors"
 	log "github.com/sirupsen/logrus"
 )
 
@@ -98,7 +99,7 @@ func (a *AdjRIBOut) AddPath(pfx bnet.Prefix, p *route.Path) error {
 	if a.addPathTX {
 		pathID, err := a.pathIDManager.addPath(p)
 		if err != nil {
-			return fmt.Errorf("Unable to get path ID: %v", err)
+			return errors.Wrap(err, "Unable to get path ID")
 		}
 
 		p.BGPPath.PathIdentifier = pathID
diff --git a/util/decode/decode.go b/util/decode/decode.go
index e6342f81..44489fbc 100644
--- a/util/decode/decode.go
+++ b/util/decode/decode.go
@@ -3,7 +3,8 @@ package decode
 import (
 	"bytes"
 	"encoding/binary"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // Decode reads fields from a buffer
@@ -12,7 +13,7 @@ func Decode(buf *bytes.Buffer, fields []interface{}) error {
 	for _, field := range fields {
 		err = binary.Read(buf, binary.BigEndian, field)
 		if err != nil {
-			return fmt.Errorf("Unable to read from buffer: %v", err)
+			return errors.Wrap(err, "Unable to read from buffer")
 		}
 	}
 	return nil
diff --git a/util/decoder/decoder.go b/util/decoder/decoder.go
index 709e3935..7891f8c2 100644
--- a/util/decoder/decoder.go
+++ b/util/decoder/decoder.go
@@ -3,7 +3,8 @@ package decoder
 import (
 	"bytes"
 	"encoding/binary"
-	"fmt"
+
+	"github.com/pkg/errors"
 )
 
 // Decode decodes network packets
@@ -12,7 +13,7 @@ func Decode(buf *bytes.Buffer, fields []interface{}) error {
 	for _, field := range fields {
 		err = binary.Read(buf, binary.BigEndian, field)
 		if err != nil {
-			return fmt.Errorf("Unable to read from buffer: %v", err)
+			return errors.Wrap(err, "Unable to read from buffer")
 		}
 	}
 	return nil
-- 
GitLab