2 * Copyright (c) 2015 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.vpnservice.arputil.internal;
11 import static com.google.common.base.Preconditions.checkArgument;
12 import static com.google.common.base.Preconditions.checkNotNull;
14 import java.math.BigInteger;
15 import java.net.InetAddress;
16 import java.net.UnknownHostException;
17 import java.util.List;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.ConcurrentMap;
20 import java.util.concurrent.ExecutorService;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.Future;
24 import org.opendaylight.controller.liblldp.NetUtils;
25 import org.opendaylight.controller.liblldp.Packet;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
28 import org.opendaylight.controller.md.sal.binding.api.NotificationService;
29 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
32 import org.opendaylight.vpnservice.mdsalutil.NWUtil;
33 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
34 import org.opendaylight.vpnservice.mdsalutil.packet.ARP;
35 import org.opendaylight.vpnservice.mdsalutil.packet.Ethernet;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
41 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketInReason;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingListener;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketProcessingService;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.PacketReceived;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.SendToController;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.packet.service.rev130709.TransmitPacketInputBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.ArpRequestReceivedBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.ArpResponseReceivedBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.GetMacInput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.GetMacOutput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.GetMacOutputBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.MacChangedBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.OdlArputilService;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpRequestInput;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpRequestInputBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.SendArpResponseInput;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.arputil.rev151126.interfaces.InterfaceAddress;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.BaseIds;
70 import org.opendaylight.yangtools.concepts.ListenerRegistration;
71 import org.opendaylight.yangtools.yang.binding.DataObject;
72 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
73 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
74 import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
75 import org.opendaylight.yangtools.yang.common.RpcResult;
76 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
80 import com.google.common.base.Optional;
81 import com.google.common.util.concurrent.FutureCallback;
82 import com.google.common.util.concurrent.Futures;
83 import com.google.common.util.concurrent.JdkFutureAdapters;
84 import com.google.common.util.concurrent.SettableFuture;
86 public class ArpUtilImpl implements OdlArputilService,
87 PacketProcessingListener, AutoCloseable {
89 private static final String FAILED_TO_GET_SRC_IP_FOR_INTERFACE = "Failed to get src ip for %s";
91 private static final String FAILED_TO_GET_SRC_MAC_FOR_INTERFACE = "Failed to get src mac for interface %s iid %s ";
93 private static final String FAILED_TO_SEND_ARP_REQ_FOR_INTERFACE = "failed to send arp req for interface ";
95 private static final String UNKNOWN_IP_ADDRESS_SUPPLIED = "unknown ip address supplied";
97 private static final String NODE_CONNECTOR_NOT_FOUND_ERROR = "Node connector id not found for interface %s";
99 private static final String DPN_NOT_FOUND_ERROR = "dpn not found for interface %s ";
101 private static final short ARP_REQUEST_OP = (short) 1;
103 private static final short ARP_RESPONSE_OP = (short) 2;
105 private static final short ETH_TYPE_ARP = 0x0806;
107 private static final Logger LOGGER = LoggerFactory
108 .getLogger(ArpUtilImpl.class);
110 ExecutorService threadPool = Executors.newFixedThreadPool(1);
112 DataBroker dataBroker;
113 PacketProcessingService packetProcessingService;
114 NotificationPublishService notificationPublishService;
115 NotificationService notificationService;
116 IMdsalApiManager mdsalMgr;
118 ListenerRegistration<ArpUtilImpl> listenerRegistration;
120 ConcurrentMap<String, String> macsDB = new ConcurrentHashMap<>();
121 ConcurrentMap<String, SettableFuture<RpcResult<GetMacOutput>>> getMacFutures = new ConcurrentHashMap<>();
123 public ArpUtilImpl(DataBroker db,
124 PacketProcessingService packetProcessingService,
125 NotificationPublishService notificationPublishService,
126 NotificationService notificationService,
127 IMdsalApiManager mdsalApiManager) {
129 this.dataBroker = db;
130 this.packetProcessingService = packetProcessingService;
131 this.notificationPublishService = notificationPublishService;
132 this.mdsalMgr = mdsalApiManager;
133 this.notificationService = notificationService;
135 listenerRegistration = notificationService
136 .registerNotificationListener(this);
137 LOGGER.info("ArpUtil Manager Initialized ");
141 public void close() throws Exception {
142 listenerRegistration.close();
143 LOGGER.trace("ArpUtil manager Closed");
146 String getIpAddressInString(IpAddress ipAddress)
147 throws UnknownHostException {
148 return InetAddress.getByName(ipAddress.getIpv4Address().getValue())
152 public Future<RpcResult<GetMacOutput>> getMac(GetMacInput input) {
155 final String dstIpAddress = getIpAddressInString(input
157 if (LOGGER.isTraceEnabled()) {
158 LOGGER.trace("getMac rpc invoked for ip " + dstIpAddress);
160 if (getMacFutures.get(dstIpAddress) != null) {
161 if (LOGGER.isInfoEnabled()) {
162 LOGGER.info("get mac already in progress for the ip "
165 return getMacFutures.get(dstIpAddress);
167 SendArpRequestInputBuilder builder = new SendArpRequestInputBuilder()
168 .setInterfaceAddress(input.getInterfaceAddress())
169 .setIpaddress(input.getIpaddress());
170 Future<RpcResult<Void>> arpReqFt = sendArpRequest(builder.build());
171 final SettableFuture<RpcResult<GetMacOutput>> ft = SettableFuture
175 JdkFutureAdapters.listenInPoolThread(arpReqFt, threadPool),
176 new FutureCallback<RpcResult<Void>>() {
178 public void onFailure(Throwable e) {
179 RpcResultBuilder<GetMacOutput> resultBuilder = RpcResultBuilder
180 .<GetMacOutput> failed().withError(
181 ErrorType.APPLICATION,
183 ft.set(resultBuilder.build());
187 public void onSuccess(RpcResult<Void> result) {
188 LOGGER.trace("Successfully sent the arp pkt out for ip "
193 getMacFutures.put(dstIpAddress, ft);
195 } catch (Exception e) {
196 LOGGER.trace("failed to handle getMac request for {} {}",
197 input.getIpaddress(), e);
198 RpcResultBuilder<GetMacOutput> resultBuilder = RpcResultBuilder
199 .<GetMacOutput> failed().withError(ErrorType.APPLICATION,
201 return Futures.immediateFuture(resultBuilder.build());
205 byte[] getIpAddressBytes(IpAddress ip) throws UnknownHostException {
206 return InetAddress.getByName(ip.getIpv4Address().getValue())
211 public Future<RpcResult<Void>> sendArpRequest(
212 SendArpRequestInput arpReqInput) {
213 if (LOGGER.isTraceEnabled()) {
214 LOGGER.trace("rpc sendArpRequest invoked for ip "
215 + arpReqInput.getIpaddress());
220 String interfaceName = null;
222 byte[] dstIpBytes = null;
224 RpcResultBuilder<Void> failureBuilder = RpcResultBuilder
226 RpcResultBuilder<Void> successBuilder = RpcResultBuilder
230 dstIpBytes = getIpAddressBytes(arpReqInput.getIpaddress());
231 } catch (Exception e) {
232 failureBuilder.withError(ErrorType.APPLICATION,
233 UNKNOWN_IP_ADDRESS_SUPPLIED);
234 return Futures.immediateFuture(failureBuilder.build());
237 int localErrorCount = 0;
238 for (InterfaceAddress interfaceAddress : arpReqInput
239 .getInterfaceAddress()) {
241 interfaceName = interfaceAddress.getInterface();
242 srcIpBytes = getIpAddressBytes(interfaceAddress.getIpAddress());
244 NodeConnectorId id = getNodeConnectorFromInterfaceName(interfaceName);
246 dpnId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(id));
247 Long portid = MDSALUtil.getOfPortNumberFromPortName(id);
248 checkArgument(null != dpnId && BigInteger.ZERO != dpnId,
249 DPN_NOT_FOUND_ERROR, interfaceName);
251 NodeConnectorRef ref = MDSALUtil.getNodeConnRef(dpnId,
253 checkNotNull(ref, NODE_CONNECTOR_NOT_FOUND_ERROR, interfaceName);
255 if (LOGGER.isTraceEnabled()) {
257 "sendArpRequest received dpnId {} out interface {}",
258 dpnId, interfaceName);
260 byte srcMac[] = MDSALUtil.getMacAddressForNodeConnector(
262 (InstanceIdentifier<NodeConnector>) ref.getValue());
263 checkNotNull(srcMac, FAILED_TO_GET_SRC_MAC_FOR_INTERFACE,
264 interfaceName, ref.getValue());
265 checkNotNull(srcIpBytes, FAILED_TO_GET_SRC_IP_FOR_INTERFACE,
268 payload = ArpPacketUtil.getPayload(ARP_REQUEST_OP, srcMac,
269 srcIpBytes, ArpPacketUtil.EthernetDestination_Broadcast,
272 sendPacketOut(dpnId, payload, ref);
274 if (LOGGER.isTraceEnabled()) {
275 LOGGER.trace("sent arp request for "
276 + arpReqInput.getIpaddress());
278 } catch (Exception e) {
279 LOGGER.trace("failed to send arp req for {} on interface {}",
280 arpReqInput.getIpaddress(), interfaceName);
283 .withError(ErrorType.APPLICATION,
284 FAILED_TO_SEND_ARP_REQ_FOR_INTERFACE
287 .withError(ErrorType.APPLICATION,
288 FAILED_TO_SEND_ARP_REQ_FOR_INTERFACE
293 if (localErrorCount == arpReqInput.getInterfaceAddress().size()) {
294 // All the requests failed
295 return Futures.immediateFuture(failureBuilder.build());
297 return Futures.immediateFuture(successBuilder.build());
300 public Future<RpcResult<Void>> sendPacketOut(BigInteger dpnId,
301 byte[] payload, NodeConnectorRef ref) {
303 NodeConnectorRef nodeConnectorRef = MDSALUtil.getNodeConnRef(dpnId,
305 return packetProcessingService
306 .transmitPacket(new TransmitPacketInputBuilder()
309 new NodeRef(InstanceIdentifier
310 .builder(Nodes.class)
312 new NodeKey(new NodeId(
313 "openflow:" + dpnId)))
315 .setIngress(nodeConnectorRef).setEgress(ref).build());
319 public Future<RpcResult<Void>> sendArpResponse(SendArpResponseInput input) {
320 if (LOGGER.isTraceEnabled()) {
321 LOGGER.trace("sendArpResponse rpc invoked");
328 String interfaceName = input.getInterface();
329 NodeConnectorId id = getNodeConnectorFromInterfaceName(interfaceName);
331 dpnId = BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(id));
332 Long portid = MDSALUtil.getOfPortNumberFromPortName(id);
334 NodeConnectorRef ref = MDSALUtil.getNodeConnRef(dpnId,
336 checkArgument(null != dpnId && BigInteger.ZERO != dpnId,
337 DPN_NOT_FOUND_ERROR, interfaceName);
338 checkNotNull(ref, NODE_CONNECTOR_NOT_FOUND_ERROR, interfaceName);
340 if (LOGGER.isTraceEnabled()) {
342 "sendArpRequest received dpnId {} out interface {}",
343 dpnId, interfaceName);
346 byte[] srcIpBytes = getIpAddressBytes(input.getSrcIpAddress());
347 byte[] dstIpBytes = getIpAddressBytes(input.getIpaddress());
348 byte srcMac[] = MDSALUtil.getMacAddressForNodeConnector(dataBroker,
349 (InstanceIdentifier<NodeConnector>) ref.getValue());
350 byte[] dstMac = NWUtil.parseMacAddress(input.getMacaddress()
352 checkNotNull(srcIpBytes, FAILED_TO_GET_SRC_IP_FOR_INTERFACE,
354 payload = ArpPacketUtil.getPayload(ARP_RESPONSE_OP, srcMac, srcIpBytes,
357 sendPacketOut(dpnId, payload, ref);
358 if (LOGGER.isTraceEnabled()) {
359 LOGGER.trace("sent the arp response for "
360 + input.getSrcIpAddress());
362 } catch (Exception e) {
363 LOGGER.trace("failed to send arp response for {} {}",
364 input.getSrcIpAddress(), e);
365 return RpcResultBuilder.<Void> failed()
366 .withError(ErrorType.APPLICATION, e.getMessage(), e)
369 RpcResultBuilder<Void> rpcResultBuilder = RpcResultBuilder.success();
370 return Futures.immediateFuture(rpcResultBuilder.build());
374 public void onPacketReceived(PacketReceived packetReceived) {
375 Class<? extends PacketInReason> pktInReason = packetReceived
376 .getPacketInReason();
377 if (LOGGER.isTraceEnabled()) {
378 LOGGER.trace("Packet Received {}", packetReceived);
381 if (pktInReason == SendToController.class) {
384 int tableId = packetReceived.getTableId().getValue();
386 byte[] data = packetReceived.getPayload();
387 Ethernet ethernet = new Ethernet();
389 ethernet.deserialize(data, 0, data.length
390 * NetUtils.NumBitsInAByte);
391 if (ethernet.getEtherType() != ETH_TYPE_ARP) {
395 Packet pkt = ethernet.getPayload();
397 InetAddress srcInetAddr = InetAddress.getByAddress(arp
398 .getSenderProtocolAddress());
399 InetAddress dstInetAddr = InetAddress.getByAddress(arp
400 .getTargetProtocolAddress());
401 byte[] srcMac = ethernet.getSourceMACAddress();
403 NodeConnectorRef ref = packetReceived.getIngress();
405 String interfaceName = MDSALUtil.getInterfaceName(ref, dataBroker);
407 checkAndFireMacChangedNotification(interfaceName, srcInetAddr,
410 macsDB.put(interfaceName + "-" + srcInetAddr.getHostAddress(),
411 NWUtil.toStringMacAddress(srcMac));
413 if (arp.getOpCode() == ARP_REQUEST_OP) {
414 fireArpReqRecvdNotification(interfaceName, srcInetAddr,
415 srcMac, dstInetAddr, tableId);
417 fireArpRespRecvdNotification(interfaceName, srcInetAddr,
420 if (getMacFutures.get(srcInetAddr.getHostAddress()) != null) {
421 threadPool.submit(new MacResponderTask(arp));
424 } catch (Exception e) {
425 LOGGER.trace("Failed to decode packet: {}", e);
430 class MacResponderTask implements Runnable {
433 MacResponderTask(ARP arp) {
440 GetMacOutputBuilder outputBuilder;
442 SettableFuture<RpcResult<GetMacOutput>> future = null;
443 RpcResultBuilder<GetMacOutput> resultBuilder;
445 srcAddr = InetAddress.getByAddress(arp
446 .getSenderProtocolAddress());
447 srcMac = NWUtil.toStringMacAddress(arp
448 .getSenderHardwareAddress());
449 future = getMacFutures.remove(srcAddr.getHostAddress());
450 if (future == null) {
451 LOGGER.trace("There are no pending mac requests.");
454 outputBuilder = new GetMacOutputBuilder()
455 .setMacaddress(new PhysAddress(srcMac));
456 resultBuilder = RpcResultBuilder.success(outputBuilder.build());
457 if (LOGGER.isTraceEnabled()) {
458 LOGGER.trace("sent the mac response for ip {}",
459 srcAddr.getHostAddress());
461 } catch (Exception e) {
462 LOGGER.trace("failed to send mac response {} ", e);
463 resultBuilder = RpcResultBuilder.<GetMacOutput> failed()
464 .withError(ErrorType.APPLICATION, e.getMessage(), e);
466 future.set(resultBuilder.build());
470 private void fireArpRespRecvdNotification(String interfaceName,
471 InetAddress inetAddr, byte[] macAddressBytes, int tableId)
472 throws InterruptedException {
474 IpAddress ip = new IpAddress(inetAddr.getHostAddress().toCharArray());
475 String macAddress = NWUtil.toStringMacAddress(macAddressBytes);
476 PhysAddress mac = new PhysAddress(macAddress);
477 ArpResponseReceivedBuilder builder = new ArpResponseReceivedBuilder();
478 builder.setInterface(interfaceName);
479 builder.setIpaddress(ip);
480 builder.setOfTableId((long) tableId);
481 builder.setMacaddress(mac);
482 notificationPublishService.putNotification(builder.build());
485 private void fireArpReqRecvdNotification(String interfaceName,
486 InetAddress srcInetAddr, byte[] srcMac, InetAddress dstInetAddr,
487 int tableId) throws InterruptedException {
488 String macAddress = NWUtil.toStringMacAddress(srcMac);
489 ArpRequestReceivedBuilder builder = new ArpRequestReceivedBuilder();
490 builder.setInterface(interfaceName);
491 builder.setOfTableId((long) tableId);
492 builder.setSrcIpaddress(new IpAddress(srcInetAddr.getHostAddress()
494 builder.setDstIpaddress(new IpAddress(dstInetAddr.getHostAddress()
496 builder.setSrcMac(new PhysAddress(macAddress));
497 notificationPublishService.putNotification(builder.build());
500 private void checkAndFireMacChangedNotification(String interfaceName,
501 InetAddress inetAddr, byte[] macAddressBytes)
502 throws InterruptedException {
504 IpAddress ip = new IpAddress(inetAddr.getHostAddress().toCharArray());
505 String macAddress = NWUtil.toStringMacAddress(macAddressBytes);
506 PhysAddress mac = new PhysAddress(macAddress);
508 if (!macAddress.equals(macsDB.get(interfaceName + "-"
509 + inetAddr.getHostAddress()))) {
510 if (LOGGER.isTraceEnabled()) {
511 LOGGER.trace("mac address changed for " + inetAddr);
513 MacChangedBuilder builder = new MacChangedBuilder();
514 builder.setInterface(interfaceName);
515 builder.setIpaddress(ip);
516 builder.setMacaddress(mac);
517 notificationPublishService.putNotification(builder.build());
521 private InstanceIdentifier<Interface> buildInterfaceId(String interfaceName) {
522 InstanceIdentifierBuilder<Interface> idBuilder = InstanceIdentifier
523 .builder(Interfaces.class).child(Interface.class,
524 new InterfaceKey(interfaceName));
525 InstanceIdentifier<Interface> id = idBuilder.build();
530 private NodeConnectorId getNodeConnectorFromInterfaceName(String interfaceName) {
531 InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder =
532 InstanceIdentifier.builder(InterfacesState.class)
533 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
534 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName));
535 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateId = idBuilder.build();
537 Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> ifStateOptional = MDSALUtil.read(dataBroker,
538 LogicalDatastoreType.OPERATIONAL,
541 if (ifStateOptional.isPresent()) {
542 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface ifState = ifStateOptional.get();
543 List<String> lowerLayerIf = ifState.getLowerLayerIf();
544 if (!lowerLayerIf.isEmpty()) {
545 return new NodeConnectorId(lowerLayerIf.get(0));