[MDSAL-131] toString() throws exception for 'type binary' binding Created: 02/Mar/16  Updated: 08/Apr/22  Resolved: 13/May/16

Status: Verified
Project: mdsal
Component/s: None
Affects Version/s: None
Fix Version/s: None

Type: Bug
Reporter: Lori Jakab Assignee: Peter Kajsa
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Operating System: All
Platform: All


External issue ID: 5446
Priority: Normal

 Description   

In the lispflowmapping project we're trying to add support for binary IPv4 and IPv6 address types to use internally to improve performance when we don't need a string representation of the addresses. (See lines 24-51 in https://git.opendaylight.org/gerrit/gitweb?p=lispflowmapping.git;a=blob;f=mappingservice/lisp-proto/src/main/yang/odl-lisp-proto.yang;h=58bf372611c9937ec6c9a373966a3c8275f548a4;hb=HEAD) However, when we do try to get a string representation of the binary object, we get the following stack trace:

2016-03-01 15:47:28,756 | ERROR | pool-28-thread-1 | DOMNotificationRouterEvent       | 140 - org.opendaylight.controller.sal-broker-impl - 1.4.0.SNAPSHOT | Delivery of notification org.opendaylight.controller.md.sal.binding.impl.LazySerializedDOMNotification@352556f7 caused an error in listener org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationListenerAdapter@1c213c0c
java.lang.IllegalStateException: Could not construct instance
	at org.opendaylight.yangtools.binding.data.codec.impl.UnionTypeCodec.deserialize(UnionTypeCodec.java:71)[91:org.opendaylight.mdsal.binding-dom-codec:0.9.0.SNAPSHOT]
	at org.opendaylight.yangtools.binding.data.codec.impl.LeafNodeCodecContext.deserializeObject(LeafNodeCodecContext.java:199)[91:org.opendaylight.mdsal.binding-dom-codec:0.9.0.SNAPSHOT]
	at org.opendaylight.yangtools.binding.data.codec.impl.DataObjectCodecContext.getBindingChildValue(DataObjectCodecContext.java:329)[91:org.opendaylight.mdsal.binding-dom-codec:0.9.0.SNAPSHOT]
	at org.opendaylight.yangtools.binding.data.codec.impl.LazyDataObject.getBindingData(LazyDataObject.java:122)[91:org.opendaylight.mdsal.binding-dom-codec:0.9.0.SNAPSHOT]
	at org.opendaylight.yangtools.binding.data.codec.impl.LazyDataObject.invoke(LazyDataObject.java:69)[91:org.opendaylight.mdsal.binding-dom-codec:0.9.0.SNAPSHOT]
	at com.sun.proxy.$Proxy86.getSourceRloc(Unknown Source)[237:org.opendaylight.lispflowmapping.mappingservice.lisp-proto:1.4.0.SNAPSHOT]
	at org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.mapping.record.container.MappingRecordBuilder$MappingRecordImpl.equals(MappingRecordBuilder.java:462)[237:org.opendaylight.lispflowmapping.mappingservice.lisp-proto:1.4.0.SNAPSHOT]
	at org.opendaylight.lispflowmapping.implementation.lisp.MapServer.handleMapRegister(MapServer.java:116)[240:org.opendaylight.lispflowmapping.mappingservice.implementation:1.4.0.SNAPSHOT]
	at org.opendaylight.lispflowmapping.implementation.LispMappingService.handleMapRegister(LispMappingService.java:156)[240:org.opendaylight.lispflowmapping.mappingservice.implementation:1.4.0.SNAPSHOT]
	at org.opendaylight.lispflowmapping.implementation.LispMappingService.onAddMapping(LispMappingService.java:184)[240:org.opendaylight.lispflowmapping.mappingservice.implementation:1.4.0.SNAPSHOT]
	at org.opendaylight.yangtools.yang.binding.util.NotificationListenerInvoker.invokeNotification(NotificationListenerInvoker.java:91)[70:org.opendaylight.mdsal.yang-binding:0.9.0.SNAPSHOT]
	at org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationListenerAdapter.onNotification(BindingDOMNotificationListenerAdapter.java:44)[142:org.opendaylight.controller.sal-binding-broker-impl:1.4.0.SNAPSHOT]
	at org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouterEvent.deliverNotification(DOMNotificationRouterEvent.java:56)[140:org.opendaylight.controller.sal-broker-impl:1.4.0.SNAPSHOT]
	at org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter$1.onEvent(DOMNotificationRouter.java:68)[140:org.opendaylight.controller.sal-broker-impl:1.4.0.SNAPSHOT]
	at org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter$1.onEvent(DOMNotificationRouter.java:65)[140:org.opendaylight.controller.sal-broker-impl:1.4.0.SNAPSHOT]
	at com.lmax.disruptor.BatchEventProcessor.run(BatchEventProcessor.java:128)[137:com.lmax.disruptor:3.3.2]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)[:1.8.0_74]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)[:1.8.0_74]
	at java.lang.Thread.run(Thread.java:745)[:1.8.0_74]
Caused by: java.lang.reflect.InvocationTargetException
	at sun.reflect.GeneratedConstructorAccessor75.newInstance(Unknown Source)[:1.8.0_74]
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)[:1.8.0_74]
	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)[:1.8.0_74]
	at org.opendaylight.yangtools.binding.data.codec.impl.UnionTypeCodec.deserialize(UnionTypeCodec.java:69)[91:org.opendaylight.mdsal.binding-dom-codec:0.9.0.SNAPSHOT]
	... 18 more
Caused by: java.lang.IllegalArgumentException: com.google.common.io.BaseEncoding$DecodingException: Unrecognized character: [
	at com.google.common.io.BaseEncoding.decode(BaseEncoding.java:228)[62:com.google.guava:18.0.0]
	at org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.Ipv4AddressBinary.getDefaultInstance(Ipv4AddressBinary.java:51)[237:org.opendaylight.lispflowmapping.mappingservice.lisp-proto:1.4.0.SNAPSHOT]
	at org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.IpAddressBinaryBuilder.getDefaultInstance(IpAddressBinaryBuilder.java:16)[237:org.opendaylight.lispflowmapping.mappingservice.lisp-proto:1.4.0.SNAPSHOT]
	at org.opendaylight.yang.gen.v1.urn.opendaylight.lfm.lisp.proto.rev151105.IpAddressBinary.<init>(IpAddressBinary.java:37)[237:org.opendaylight.lispflowmapping.mappingservice.lisp-proto:1.4.0.SNAPSHOT]
	... 22 more
Caused by: com.google.common.io.BaseEncoding$DecodingException: Unrecognized character: [
	at com.google.common.io.BaseEncoding$Alphabet.decode(BaseEncoding.java:503)[62:com.google.guava:18.0.0]
	at com.google.common.io.BaseEncoding$StandardBaseEncoding$2.read(BaseEncoding.java:675)[62:com.google.guava:18.0.0]
	at com.google.common.io.BaseEncoding.decodeChecked(BaseEncoding.java:245)[62:com.google.guava:18.0.0]
	at com.google.common.io.BaseEncoding.decode(BaseEncoding.java:226)[62:com.google.guava:18.0.0]
	... 25 more


 Comments   
Comment by Tony Tkacik [ 02/Mar/16 ]

Could you please point to the model which triggered this and also binary data you were trying to set?

Comment by Lori Jakab [ 03/Mar/16 ]

The module is odl-lisp-proto.yang, lines 24-51, see my initial report for a link to gitweb. The binary data we tried to set was an byte[] taken from am InetAddress. The problem happens not when trying to set it, but when it has to be converted to text with .toString().

Comment by zhuweisheng [ 24/Mar/16 ]

From the error log, may be you use Ipv4AddressBinary.getDefaultInstance("XXXX") to set binary data, and the "XXXX" contains '[', so you have the error.

Comment by Vina Ermagan [ 22/Apr/16 ]

Any updates on this? Would really appreciate a fix.

Thanks,
Vina

Comment by Lori Jakab [ 25/Apr/16 ]

(In reply to Tony Tkacik from comment #1)
> Could you please point to the model which triggered this and also binary
> data you were trying to set?

On line 42 of the model that I linked to in the original bug report (odl-lisp-proto.yang) I'm defining a union of two binary types ipv4-address-binary and ipv6-address-binary as ip-address-binary. Yangtools autogenerates the IpAddressBinaryBuilder.java file under src/main/java instead of generated-sources/mdsal-binding, because it needs to be implemented. The implementation looks like this:

https://git.opendaylight.org/gerrit/gitweb?p=lispflowmapping.git;a=blob;f=mappingservice/lisp-proto/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/lfm/lisp/proto/rev151105/IpAddressBinaryBuilder.java;h=810d6cf7be2048e17ff0fd5d52be53817a23f906;hb=HEAD

Robert gave a quick look at the implementation (at the design forum), and said it should work as-is. However, if I try a IpAddressBinaryBuilder.getDefaultInstance("127.0.0.1") for example, I will get an exception.

The exception from the original bug report for example is trying to log a packet address, where the address is stored in an Ipv4AddressBinary type.

Comment by Lori Jakab [ 25/Apr/16 ]

Some additional info, I retested things, since the original report was a while ago. When I add an Ipv4AddressBinary object to the datastore and read it back with RESTCONF, it is represented like this: "fwAAAQ==", which is the expected base64 encoding of the binary data (127.0.0.1). However, an IpAddressBinary object, which is the union, looks like this: "[B@6fadb49c" which looks an awful lot like a reference instead of the object inside. Hope this helps fix the bug quicker.

Comment by Peter Kajsa [ 04/May/16 ]

fix:
master - https://git.opendaylight.org/gerrit/#/c/38272/
Be - https://git.opendaylight.org/gerrit/#/c/38358/

Comment by Lori Jakab [ 04/May/16 ]

(In reply to Peter Kajsa from comment #7)
> fix:
> master - https://git.opendaylight.org/gerrit/#/c/38272/
> Be - https://git.opendaylight.org/gerrit/#/c/38358/

I just tried the suggested fix. I still see "[B@125afdf3" for an ip-address-binary based field in RESTCONF output. The _value member in the IpAddressBinary object however looks ok. Here's some code I used to test the logging output, after reading an IPv4 address from a packet:

if (sourceRloc instanceof Inet4Address) {
Ipv4AddressBinary ipv4 = new Ipv4AddressBinary(sourceRloc.getAddress());
IpAddressBinary ip = new IpAddressBinary(ipv4);
LOG.info("Ipv4AddressBinary: {} | IpAddressBinary: {}", ipv4, ip);
}

The output looks like this:

2016-05-04 12:55:09,426 | INFO | lisp-sb-6-1 | MapRegisterSerializer | 255 - org.opendaylight.lispflowmapping.mappingservice.lisp-proto - 1.4.0.SNAPSHOT | Ipv4AddressBinary: Ipv4AddressBinary [_value=[127, 0, 0, 1]] | IpAddressBinary: IpAddressBinary [_ipv4AddressBinary=Ipv4AddressBinary [_value=[127, 0, 0, 1]], _value=[f, w, A, A, A, Q, =, =]]

RESTCONF output still shows the memory reference.

I just pushed some code that I use for RESTCONF testing here:
https://github.com/ljakab/lispflowmapping/tree/ip-address-binary

Comment by Peter Kajsa [ 04/May/16 ]

Please let us know, whether the exception from your first comment (java.lang.IllegalStateException: Could not construct instance ...) still persists ? I think it should be ok now.

However, there could be the same problem somewhere in Restconf as well, so we will look at it.

Comment by Lori Jakab [ 04/May/16 ]

(In reply to Peter Kajsa from comment #9)
> Please let us know, whether the exception from your first comment
> (java.lang.IllegalStateException: Could not construct instance ...) still
> persists ? I think it should be ok now.

I can't reproduce that exception anymore, so I think it's ok.

>
> However, there could be the same problem somewhere in Restconf as well, so
> we will look at it.

Thanks!

Comment by Lori Jakab [ 06/May/16 ]

(In reply to Lori Jakab from comment #10)
> (In reply to Peter Kajsa from comment #9)
> > Please let us know, whether the exception from your first comment
> > (java.lang.IllegalStateException: Could not construct instance ...) still
> > persists ? I think it should be ok now.
>
> I can't reproduce that exception anymore, so I think it's ok.

Actually, now that I tried to build some code using the union, I still see issues regardless of RESTCONF. You can take a look at the unit tests from the mappingservice.implementation module after applying this patch https://git.opendaylight.org/gerrit/#/c/38496/

LispMappingServiceTest.onAddMappingTest_noTransportAddress:196
Argument(s) are different! Wanted:
lispSB.sendMapNotify(
SendMapNotifyInput [_mapNotify=MapNotify [_keyId=1, augmentation=[]], _transportAddress=TransportAddress [_ipAddress=IpAddressBinary [_ipv4AddressBinary=Ipv4AddressBinary [_value=[1, 2, 3, 0]], _value=[[, B, @, 4, d, 0, 4, 0, 2, b]], _port=PortNumber [_value=4342], augmentation=[]], augmentation=[]]
);
-> at org.opendaylight.lispflowmapping.implementation.LispMappingServiceTest.onAddMappingTest_noTransportAddress(LispMappingServiceTest.java:196)
Actual invocation has different arguments:
lispSB.sendMapNotify(
SendMapNotifyInput [_mapNotify=MapNotify [_keyId=1, augmentation=[]], _transportAddress=TransportAddress [_ipAddress=IpAddressBinary [_ipv4AddressBinary=Ipv4AddressBinary [_value=[1, 2, 3, 0]], _value=[[, B, @, 1, 6, 0, c, 3, e, c, 1]], _port=PortNumber [_value=4342], augmentation=[]], augmentation=[]]

If you take a look at the IpAddressBinary _value, it still shows a memory reference instead of a base64 string.

Comment by Lori Jakab [ 06/May/16 ]

(In reply to Lori Jakab from comment #11)
> If you take a look at the IpAddressBinary _value, it still shows a memory
> reference instead of a base64 string.

Or the bytes themselves, as it's shown for Ipv4AddressBinary _value.

Comment by Peter Kajsa [ 12/May/16 ]

Yangtools union codec fix: https://git.opendaylight.org/gerrit/#/c/38669/

Comment by Peter Kajsa [ 12/May/16 ]

Please retest with the both patches and let us know the result. Thanks.
MD-SAL: https://git.opendaylight.org/gerrit/#/c/38272/
Yangtools: https://git.opendaylight.org/gerrit/#/c/38669/

Comment by Lori Jakab [ 12/May/16 ]

The two patches together fix all issues, including correct encoding in RESTCONF output. Thanks!

Comment by Robert Varga [ 12/May/16 ]

mdsal Be: https://git.opendaylight.org/gerrit/38358

yangtools need a manual cherry-pick.

Comment by Peter Kajsa [ 13/May/16 ]

Yangtools Be: https://git.opendaylight.org/gerrit/#/c/38853/1

Generated at Wed Feb 07 20:08:43 UTC 2024 using Jira 8.20.10#820010-sha1:ace47f9899e9ee25d7157d59aa17ab06aee30d3d.