2 * Copyright (c) 2014, 2015 NEC Corporation. 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.vtn.manager.internal.cluster;
12 import java.util.concurrent.ConcurrentMap;
14 import org.slf4j.Logger;
16 import org.opendaylight.vtn.manager.IVTNManagerAware;
17 import org.opendaylight.vtn.manager.PortMap;
18 import org.opendaylight.vtn.manager.PortMapConfig;
19 import org.opendaylight.vtn.manager.SwitchPort;
20 import org.opendaylight.vtn.manager.VInterface;
21 import org.opendaylight.vtn.manager.VInterfaceConfig;
22 import org.opendaylight.vtn.manager.VInterfacePath;
23 import org.opendaylight.vtn.manager.VNodePath;
24 import org.opendaylight.vtn.manager.VNodeRoute;
25 import org.opendaylight.vtn.manager.VTNException;
26 import org.opendaylight.vtn.manager.VTenantPath;
27 import org.opendaylight.vtn.manager.util.EtherAddress;
29 import org.opendaylight.vtn.manager.internal.IVTNResourceManager;
30 import org.opendaylight.vtn.manager.internal.VTNManagerProvider;
31 import org.opendaylight.vtn.manager.internal.PacketContext;
32 import org.opendaylight.vtn.manager.internal.TxContext;
33 import org.opendaylight.vtn.manager.internal.VTNManagerImpl;
34 import org.opendaylight.vtn.manager.internal.VTNConfig;
35 import org.opendaylight.vtn.manager.internal.VTNThreadData;
36 import org.opendaylight.vtn.manager.internal.inventory.VtnNodeEvent;
37 import org.opendaylight.vtn.manager.internal.inventory.VtnPortEvent;
38 import org.opendaylight.vtn.manager.internal.util.ProtocolUtils;
39 import org.opendaylight.vtn.manager.internal.util.flow.match.VTNEtherMatch;
40 import org.opendaylight.vtn.manager.internal.util.flow.match.VTNMatch;
41 import org.opendaylight.vtn.manager.internal.util.inventory.InventoryReader;
42 import org.opendaylight.vtn.manager.internal.util.inventory.InventoryUtils;
43 import org.opendaylight.vtn.manager.internal.util.inventory.NodeUtils;
44 import org.opendaylight.vtn.manager.internal.util.inventory.SalNode;
45 import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
46 import org.opendaylight.vtn.manager.internal.util.rpc.RpcException;
47 import org.opendaylight.vtn.manager.internal.util.flow.VTNFlowBuilder;
49 import org.opendaylight.controller.sal.core.Node;
50 import org.opendaylight.controller.sal.core.NodeConnector;
51 import org.opendaylight.controller.sal.core.UpdateType;
52 import org.opendaylight.controller.sal.packet.Ethernet;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.flow.rev150410.VirtualRouteReason;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPort;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VnodeState;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnErrorTag;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnUpdateType;
61 * Implementation of virtual interface that can have port mapping
65 * Although this class is public to other packages, this class does not
66 * provide any API. Applications other than VTN Manager must not use this
70 public abstract class PortInterface extends AbstractInterface
71 implements VirtualMapNode, FlowFilterNode {
73 * Version number for serialization.
75 private static final long serialVersionUID = 3346949601083788579L;
78 * Port mapping configuration.
80 private PortMapConfig portMapConfig;
83 * Flow filters for incoming packets.
85 private final FlowFilterMap inFlowFilters;
88 * Flow filters for outgoing packets.
90 private final FlowFilterMap outFlowFilters;
93 * Construct a virtual node instance that can have port mapping.
95 * @param parent The parent node that contains this node.
96 * @param name The name of this node.
97 * @param iconf Configuration for the interface.
99 protected PortInterface(AbstractBridge parent, String name,
100 VInterfaceConfig iconf) {
101 super(parent, name, iconf);
102 inFlowFilters = FlowFilterMap.createIncoming(this);
103 outFlowFilters = FlowFilterMap.createOutgoing(this);
107 * Return the port mapping information.
110 * This method assumes that the call of this method is synchronized
111 * by the parent node.
114 * @param mgr VTN Manager service.
115 * @return Port mapping information. {@code null} is returned if the
116 * port mapping is not configured on this node.
118 final PortMap getPortMap(VTNManagerImpl mgr) {
119 PortMapConfig pmconf = portMapConfig;
120 if (pmconf == null) {
124 return new PortMap(pmconf, getMappedPort(mgr));
128 * Return a node connector associated with the switch port mapped to
132 * This method assumes that the call of this method is synchronized
133 * by the parent node.
136 * @param mgr VTN Manager service.
137 * @return A node connector. {@code null} is returned if no swtich port
140 final NodeConnector getMappedPort(VTNManagerImpl mgr) {
141 VInterfaceState ist = getIfState(mgr);
142 return ist.getMappedPort();
146 * Create or destroy mapping between the physical switch port and this
150 * This method assumes that the call of this method is synchronized
151 * by the parent node.
154 * @param mgr VTN Manager service.
155 * @param ctx MD-SAL datastore transaction context.
156 * @param pmconf Port mapping configuration to be set.
157 * If {@code null} is specified, port mapping on the
158 * specified interface is destroyed.
159 * @return New state of this virtual interface.
160 * {@code null} is returned if the port mapping configuration
162 * @throws VTNException An error occurred.
164 final VnodeState setPortMap(VTNManagerImpl mgr, TxContext ctx,
165 PortMapConfig pmconf)
166 throws VTNException {
167 ConcurrentMap<VTenantPath, Object> db = mgr.getStateDB();
168 VInterfaceState ist = getIfState(db);
170 if (pmconf == null) {
171 // Destroy port mapping.
172 return unsetPortMap(mgr, db, ist);
175 PortMapConfig oldconf = portMapConfig;
176 if (pmconf.equals(oldconf)) {
181 Node node = pmconf.getNode();
182 NodeUtils.checkNode(node);
184 short vlan = pmconf.getVlan();
185 ProtocolUtils.checkVlan(vlan);
187 SwitchPort port = pmconf.getPort();
188 NodeUtils.checkSwitchPort(port, node);
190 NodeConnector mapped = ist.getMappedPort();
191 IVTNResourceManager resMgr = mgr.getResourceManager();
192 PortVlan pvlan = null;
194 // Search for the switch port specified by the configuration.
195 InventoryReader reader = ctx.getInventoryReader();
197 SalPort sport = reader.findPort(node, port);
199 nc = sport.getAdNodeConnector();
200 if (nc.equals(mapped) && oldconf.getVlan() == vlan) {
201 // No need to change switch port mapping.
202 portMapConfig = pmconf;
203 return ist.getState();
206 pvlan = new PortVlan(nc, vlan);
211 PortVlan rmlan = (mapped == null)
213 : new PortVlan(mapped, oldconf.getVlan());
215 // Register port mapping, and unregister old port mapping if needed.
216 VInterfacePath path = getInterfacePath();
219 ref = resMgr.registerPortMap(mgr, path, pvlan, rmlan, true);
220 } catch (VTNException e) {
221 VtnErrorTag etag = e.getVtnErrorTag();
222 if (etag == VtnErrorTag.INTERNALERROR) {
223 mgr.logException(getLogger(), (VNodePath)path, e, pvlan,
230 assert ref.getMapType() == MapType.PORT;
232 throw RpcException.getDataExistsException(
233 "Specified port is mapped to " + ref.getAbsolutePath());
236 // Update the state of this node.
237 portMapConfig = pmconf;
238 ist.setMappedPort(nc);
239 PortMap pmap = new PortMap(pmconf, nc);
240 if (oldconf == null) {
241 PortMapEvent.added(mgr, path, pmap);
243 PortMapEvent.changed(mgr, path, pmap, true);
248 state = getNewState(reader, ist);
250 state = VnodeState.DOWN;
251 VnodeState pstate = getPortState(reader, sport);
252 ist.setPortState(pstate);
255 db.put((VNodePath)path, ist);
257 VnodeState pstate = ist.getPortState();
258 VInterface viface = new VInterface(getName(), state, pstate,
259 getVInterfaceConfig());
260 VInterfaceEvent.changed(mgr, path, viface, false);
267 * Invoked when a node is added, removed, or changed.
269 * @param mgr VTN Manager service.
270 * @param db Virtual node state DB.
271 * @param prstate Current state of the parent node.
272 * @param ev A {@link VtnNodeEvent} instance.
273 * @return New state of the parent node.
275 final VnodeState notifyNode(VTNManagerImpl mgr,
276 ConcurrentMap<VTenantPath, Object> db,
277 VnodeState prstate, VtnNodeEvent ev) {
278 VnodeState state = notifyNode(mgr, db, ev);
279 return getParentState(state, prstate);
283 * This method is called when some properties of a node connector are
284 * added/deleted/changed.
286 * @param mgr VTN Manager service.
287 * @param db Virtual node state DB.
288 * @param prstate Current state of the parent node.
289 * @param ev {@link VtnPortEvent} instance.
290 * @return New state of this virtual node.
292 final VnodeState notifyNodeConnector(VTNManagerImpl mgr,
293 ConcurrentMap<VTenantPath, Object> db,
294 VnodeState prstate, VtnPortEvent ev) {
295 VnodeState state = notifyNodeConnector(mgr, db, ev);
296 return getParentState(state, prstate);
300 * Determine whether the received packet should be treated as input of
301 * this virtual node or not.
304 * Note that this method does not see the state of this node.
305 * This method returns {@code true} if the network specified by the
306 * switch port and the VLAN ID is mapped to this node.
309 * @param mgr VTN Manager service.
310 * @param nc A node connector where the packet was received.
311 * @param vlan VLAN ID in the received packet.
312 * @return {@code true} is returned only if the received packet should be
313 * treated as input of this node.
315 final boolean match(VTNManagerImpl mgr, NodeConnector nc, short vlan) {
316 PortMapConfig pmconf = portMapConfig;
317 if (pmconf == null) {
321 VInterfaceState ist = getIfState(mgr);
322 NodeConnector mapped = ist.getMappedPort();
323 return (nc.equals(mapped) && pmconf.getVlan() == vlan);
327 * Transmit the specified packet to this node.
329 * @param mgr VTN manager service.
330 * @param pctx The context of the packet.
331 * @param sent A set of {@link PortVlan} which indicates the network
333 * @throws RedirectFlowException
334 * The given packet was redirected by a flow filter.
336 final void transmit(VTNManagerImpl mgr, PacketContext pctx,
337 Set<PortVlan> sent) throws RedirectFlowException {
338 PortMapConfig pmconf = portMapConfig;
339 if (pmconf == null) {
343 VInterfaceState ist = getIfState(mgr);
344 VnodeState state = ist.getState();
345 if (state != VnodeState.UP) {
349 NodeConnector mapped = ist.getMappedPort();
350 if (mapped == null) {
353 SalPort egress = SalPort.create(mapped);
354 if (egress == null) {
355 // This should never happen.
359 short vlan = pmconf.getVlan();
360 PortVlan pvlan = new PortVlan(mapped, vlan);
361 if (!sent.add(pvlan)) {
366 Logger logger = getLogger();
370 // Apply outgoing flow filters.
371 pc = outFlowFilters.evaluate(mgr, pctx, vlan);
373 // Create a new Ethernet frame to be transmitted.
374 frame = pc.createFrame(vlan);
375 } catch (DropFlowException e) {
376 // Filtered out by DROP filter.
378 } catch (Exception e) {
379 mgr.logException(logger, getPath(), e);
383 if (logger.isTraceEnabled()) {
384 VInterfacePath path = getInterfacePath();
385 logger.trace("{}:{}: Transmit packet to {} interface: {}",
386 getContainerName(), path, path.getNodeType(),
387 pc.getDescription(frame, egress, vlan));
390 mgr.transmit(egress, frame);
394 * Return the flow filter instance configured in this virtual interface.
397 * This method must be called with holding the node lock.
400 * @param out {@code true} means that the outgoing flow filter.
401 * {@code false} means that the incoming flow filter.
402 * @return A {@link FlowFilterMap} instance.
404 final FlowFilterMap getFlowFilterMap(boolean out) {
405 return (out) ? outFlowFilters : inFlowFilters;
409 * Flush cached network data associated with the network specified by
410 * a pair of switch port and VLAN ID.
413 * This method is used to flush network data cached by obsolete port
417 * @param mgr VTN Manager service.
418 * @param port A node connector associated with a switch port.
419 * @param vlan A VLAN ID.
421 protected void flushCache(VTNManagerImpl mgr, NodeConnector port,
423 VNodePath npath = getPath();
425 // Remove flow entries relevant to obsolete port mapping.
426 VTNThreadData.removeFlows(mgr, npath.getTenantName(), port, vlan);
429 // Remove flow entries affected by this virtual node.
430 VTNThreadData.removeFlows(mgr, npath);
434 * Redirect the packet to this virtual interface as outgoing packet.
436 * @param mgr VTN Manager service.
437 * @param pctx The context of the packet to be redirected.
438 * @param rex An exception that keeps information about the packet
440 * @param bridge A {@link PortBridge} instance associated with this
442 * @throws DropFlowException
443 * The given packet was discarded by a DROP flow filter.
444 * @throws RedirectFlowException
445 * The given packet was redirected by a REDIRECT flow filter.
446 * @throws VTNException An error occurred.
448 protected void redirect(VTNManagerImpl mgr, PacketContext pctx,
449 RedirectFlowException rex, PortBridge<?> bridge)
450 throws DropFlowException, RedirectFlowException, VTNException {
451 // Ensure that a physical switch port is mapped by port mapping.
452 PortMapConfig pmconf = portMapConfig;
453 NodeConnector mapped = getMappedPort(mgr);
454 if (pmconf == null || mapped == null) {
456 throw new DropFlowException();
459 // Evaluate flow filters for outgoing packets.
460 // Note that this should never clone a PacketContext.
461 short vlan = pmconf.getVlan();
462 outFlowFilters.evaluate(mgr, pctx, vlan);
464 // Forward the packet.
465 bridge.forward(mgr, pctx, mapped, vlan);
469 * Return a VLAN ID mapped to this virtual interface.
471 * @return A VLAN ID mapped to this interface.
472 * A negative value is returned if port mapping is not configured.
474 public short getVlan() {
475 PortMapConfig pmconf = portMapConfig;
476 return (pmconf == null) ? -1 : pmconf.getVlan();
480 * Derive new node state from the specified node connector.
483 * Note that this method may update the state of the mapped switch port
487 * @param rdr An {@link InventoryReader} instance.
488 * @param ist Runtime state of this node.
489 * @return New node state.
490 * @throws VTNException An error occurred.
492 private VnodeState getNewState(InventoryReader rdr, VInterfaceState ist)
493 throws VTNException {
494 NodeConnector nc = ist.getMappedPort();
496 return VnodeState.DOWN;
499 SalPort sport = SalPort.create(nc);
501 // This should never happen.
502 return VnodeState.DOWN;
505 VtnPort vport = rdr.get(sport);
506 return getNewState(ist, vport);
510 * Derive new node state from the specified node connector.
513 * Note that this method always updates the state of the mapped switch
514 * port in {@code ist}.
517 * @param ist Runtime state of this node.
518 * @param vport A {@link VtnPort} instance associated with the switch
519 * port mapped to this node.
520 * @return New node state.
522 private VnodeState getNewState(VInterfaceState ist, VtnPort vport) {
523 // Update the state of the mapped port.
524 VnodeState pstate = getPortState(vport);
525 ist.setPortState(pstate);
527 if (pstate == VnodeState.UP && InventoryUtils.isEdge(vport)) {
528 return VnodeState.UP;
531 return VnodeState.DOWN;
535 * Get state of the switch port.
537 * @param reader A {@link InventoryReader} instance.
538 * @param sport A {@link SalPort} instance.
539 * @return A {@link VnodeState} instance which represents the state of
540 * the specified switc port.
541 * @throws VTNException An error occurred.
543 private VnodeState getPortState(InventoryReader reader, SalPort sport)
544 throws VTNException {
546 return VnodeState.UNKNOWN;
549 VtnPort vport = reader.get(sport);
550 return getPortState(vport);
554 * Get state of the switch port.
556 * @param vport A {@link VtnPort} instance.
557 * @return A {@link VnodeState} instance which represents the state of
558 * the specified switc port.
560 private VnodeState getPortState(VtnPort vport) {
562 return VnodeState.UNKNOWN;
565 return (InventoryUtils.isEnabled(vport))
566 ? VnodeState.UP : VnodeState.DOWN;
570 * Destroy mapping between the physical switch port and this node.
572 * @param mgr VTN Manager service.
573 * @param db Virtual node state DB.
574 * @param ist Runtime state of this node.
575 * @return New state of this virtual node.
576 * {@code null} is returned if the port mapping configuration
579 private VnodeState unsetPortMap(VTNManagerImpl mgr,
580 ConcurrentMap<VTenantPath, Object> db,
581 VInterfaceState ist) {
582 PortMapConfig pmconf = portMapConfig;
583 if (pmconf == null) {
587 NodeConnector mapped = ist.getMappedPort();
588 if (mapped != null) {
589 unmapPort(mgr, db, ist, false, true);
592 portMapConfig = null;
593 PortMap pmap = new PortMap(pmconf, mapped);
594 VInterfacePath path = getInterfacePath();
595 PortMapEvent.removed(mgr, path, pmap, true);
596 setState(mgr, db, ist, VnodeState.UNKNOWN);
598 return VnodeState.UNKNOWN;
602 * Determine whether the node connector satisfies the condition specified
603 * by the port map configuration.
605 * @param pmconf Port mapping configuration.
606 * @param sport A {@link SalPort} instance.
607 * @param vport A {@link VtnPort} instance.
608 * @return {@code true} is returned only if the given node connector
609 * satisfies the condition.
611 private boolean portMatch(PortMapConfig pmconf, SalPort sport,
613 Node pnode = pmconf.getNode();
614 SwitchPort port = pmconf.getPort();
615 String type = port.getType();
616 String id = port.getId();
617 NodeConnector nc = sport.getAdNodeConnector();
618 if (type != null && id != null) {
619 // This should never return null.
620 NodeConnector target =
621 NodeConnector.fromStringNoNode(type, id, pnode);
622 if (!nc.equals(target)) {
625 } else if (!pnode.equals(nc.getNode())) {
629 String name = port.getName();
630 return (name == null || name.equals(vport.getName()));
634 * Establish port mapping.
636 * @param mgr VTN Manager service.
637 * @param db Virtual node state DB.
638 * @param ist Runtime state of this node.
639 * @param sport A {@link SalPort} to be mapped.
641 * {@code true} if this method is called by
642 * {@link #resuming(VTNManagerImpl, ConcurrentMap, TxContext, VInterfaceState)}.
643 * @return {@code true} is returned if the given port is successfully
644 * mapped. {@code false} is returned if a switch port is already
645 * mapped to this node.
647 private boolean mapPort(VTNManagerImpl mgr,
648 ConcurrentMap<VTenantPath, Object> db,
649 VInterfaceState ist, SalPort sport,
651 NodeConnector nc = sport.getAdNodeConnector();
652 short vlan = portMapConfig.getVlan();
653 PortVlan pvlan = new PortVlan(nc, vlan);
654 IVTNResourceManager resMgr = mgr.getResourceManager();
656 VInterfacePath path = getInterfacePath();
659 ref = resMgr.registerPortMap(mgr, path, pvlan, null, !resuming);
660 } catch (VTNException e) {
661 Logger logger = getLogger();
662 logger.error(getContainerName() + ":" + path +
663 ": Failed to map port to virtual interface: " +
669 ist.setMappedPort(nc);
670 db.put((VNodePath)path, ist);
676 PortMap pmap = new PortMap(portMapConfig, nc);
677 PortMapEvent.changed(mgr, path, pmap, false);
682 Logger logger = getLogger();
683 logger.error("{}:{}: Switch port is already mapped to {}: {}",
684 getContainerName(), path, ref.getAbsolutePath(), pvlan);
689 * Unmap the physical switch port currently mapped.
691 * @param mgr VTN Manager service.
692 * @param db Virtual node state DB.
693 * @param ist Runtime state of this node.
694 * @param event If {@code true} is specified, a port map event is
696 * @param purge If {@code true} is specified, network caches originated
697 * by the port mapping will be purged.
699 private void unmapPort(VTNManagerImpl mgr,
700 ConcurrentMap<VTenantPath, Object> db,
702 boolean event, boolean purge) {
703 // Unregister port mapping.
704 short vlan = portMapConfig.getVlan();
705 PortVlan pvlan = new PortVlan(ist.getMappedPort(), vlan);
706 VInterfacePath path = getInterfacePath();
707 IVTNResourceManager resMgr = mgr.getResourceManager();
709 resMgr.unregisterPortMap(mgr, path, pvlan, purge);
710 } catch (VTNException e) {
711 Logger logger = getLogger();
712 logger.error(getContainerName() + ":" + path +
713 ": Failed to unmap port: " + pvlan, e);
717 ist.setMappedPort(null);
718 db.put((VNodePath)path, ist);
724 PortMap pmap = new PortMap(portMapConfig, null);
725 PortMapEvent.changed(mgr, path, pmap, false);
730 * Invoked when a node is added, removed, or changed.
732 * @param mgr VTN Manager service.
733 * @param db Virtual node state DB.
734 * @param ev A {@link VtnNodeEvent} instance.
735 * @return New state of this interface.
737 private VnodeState notifyNode(VTNManagerImpl mgr,
738 ConcurrentMap<VTenantPath, Object> db,
740 VInterfaceState ist = getIfState(db);
741 VnodeState cur = ist.getState();
742 if (ev.getUpdateType() != VtnUpdateType.REMOVED) {
746 PortMapConfig pmconf = portMapConfig;
747 if (pmconf == null) {
751 NodeConnector mapped = ist.getMappedPort();
752 if (mapped == null) {
756 SalNode snode = ev.getSalNode();
757 Node pnode = pmconf.getNode();
758 if (pnode.equals(snode.getAdNode())) {
759 // No need to flush MAC address table entries and flow entries.
760 // It will be done by the VTN Manager service.
761 unmapPort(mgr, db, ist, true, false);
762 cur = VnodeState.DOWN;
763 setState(mgr, db, ist, cur);
770 * This method is called when some properties of a node connector are
771 * added/deleted/changed.
773 * @param mgr VTN Manager service.
774 * @param db Virtual node state DB.
775 * @param ev {@link VtnPortEvent} instance.
776 * @return New state of this virtual interface.
778 private VnodeState notifyNodeConnector(
779 VTNManagerImpl mgr, ConcurrentMap<VTenantPath, Object> db,
781 VInterfaceState ist = getIfState(db);
782 VnodeState cur = ist.getState();
783 PortMapConfig pmconf = portMapConfig;
784 if (pmconf == null) {
788 NodeConnector mapped = ist.getMappedPort();
789 VnodeState state = VnodeState.UNKNOWN;
790 SalPort sport = ev.getSalPort();
791 VtnPort vport = ev.getVtnPort();
792 switch (ev.getUpdateType()) {
794 if (mapped != null || !portMatch(pmconf, sport, vport)) {
798 // Try to establish port mapping.
799 if (!mapPort(mgr, db, ist, sport, false)) {
802 state = getNewState(ist, vport);
806 if (mapped == null) {
807 // Check whether the port name was changed.
808 // Map the port if its name matches the configuration.
809 if (pmconf.getPort().getName() == null ||
810 !portMatch(pmconf, sport, vport) ||
811 !mapPort(mgr, db, ist, sport, false)) {
815 state = getNewState(ist, vport);
816 } else if (sport.getAdNodeConnector().equals(mapped)) {
817 if (pmconf.getPort().getName() != null &&
818 !portMatch(pmconf, sport, vport)) {
819 // This port should be unmapped because its name has been
820 // changed. In this case flow and MAC address table entries
821 // need to be purged.
822 unmapPort(mgr, db, ist, true, true);
823 state = VnodeState.DOWN;
825 state = getNewState(ist, vport);
833 if (sport.getAdNodeConnector().equals(mapped)) {
834 // No need to flush MAC address table entries and flow entries.
835 // It will be done by the VTN Manager service.
836 unmapPort(mgr, db, ist, true, false);
837 state = VnodeState.DOWN;
847 setState(mgr, db, ist, state);
853 * Construct a flow match which specifies the given VLAN.
855 * @param vid A VLAN ID.
856 * @return A {@link VTNMatch} instance on success.
857 * {@code null} on failure.
859 private VTNMatch createMatch(int vid) {
861 VTNEtherMatch ematch =
862 new VTNEtherMatch(null, null, null, vid, null);
863 return new VTNMatch(ematch, null, null);
864 } catch (RpcException e) {
865 // This should never happen.
866 getLogger().error("Failed to create VLAN match: " + vid, e);
872 * Determine whether the given object is identical to this object.
874 * @param o An object to be compared.
875 * @return {@code true} if identical. Otherwise {@code false}.
878 public final boolean equals(Object o) {
882 if (!super.equals(o)) {
886 PortInterface pi = (PortInterface)o;
887 if (portMapConfig == null) {
888 return (pi.portMapConfig == null);
891 return portMapConfig.equals(pi.portMapConfig);
895 * Return the hash code of this object.
897 * @return The hash code.
900 public final int hashCode() {
901 int h = super.hashCode();
902 if (portMapConfig != null) {
903 h += (portMapConfig.hashCode() * 13);
912 * Return path to this node.
914 * @return Path to this node.
917 public VNodePath getPath() {
918 return (VNodePath)getInterfacePath();
922 * Return path to the virtual mapping which maps the given host.
925 * @param vlan Unused.
926 * @return Path to this interface.
929 public VNodePath getPath(long mac, short vlan) {
934 * Return a {@link VNodeRoute} instance which indicates the packet was
935 * mapped by the port mapping.
938 * @param vlan Unused.
939 * @return A {@link VNodeRoute} instance.
942 public final VNodeRoute getIngressRoute(long mac, short vlan) {
943 return new VNodeRoute((VNodePath)getInterfacePath(),
944 VirtualRouteReason.PORTMAPPED);
948 * Install a flow entry which drops every incoming packet.
951 * This method must be called with holding the node lock.
954 * @param mgr VTN Manager service.
955 * @param pctx The context of the received packet.
958 public final void disableInput(VTNManagerImpl mgr, PacketContext pctx) {
959 PortMapConfig pmconf = portMapConfig;
960 if (pmconf == null) {
964 VInterfaceState ist = getIfState(mgr);
965 SalPort mapped = SalPort.create(ist.getMappedPort());
966 if (mapped == null) {
970 VTNMatch vmatch = createMatch((int)pmconf.getVlan());
971 if (vmatch == null) {
975 VTNManagerProvider provider = pctx.getTxContext().getProvider();
976 VTNConfig vcfg = provider.getVTNConfig();
977 EtherAddress mac = vcfg.getControllerMacAddress();
978 int pri = vcfg.getL2FlowPriority();
979 int idle = pctx.getIdleTimeout();
980 int hard = pctx.getHardTimeout();
981 String tname = getTenantName();
983 VTNFlowBuilder builder =
984 new VTNFlowBuilder(tname, mac, vmatch, pri, idle, hard);
985 builder.addVirtualRoute(getIngressRoute(MacVlan.UNDEFINED, (short)0)).
986 setEgressVNodeRoute(null).
988 provider.addFlow(builder);
992 * Evaluate flow filters for incoming packet configured in this virtual
995 * @param mgr VTN Manager service.
996 * @param pctx The context of the received packet.
997 * @param vid A VLAN ID to be used for packet matching.
998 * A VLAN ID configured in the given packet is used if a
999 * negative value is specified.
1000 * @throws DropFlowException
1001 * The given packet was discarded by a flow filter.
1002 * @throws RedirectFlowException
1003 * The given packet was redirected by a flow filter.
1006 public final void filterPacket(VTNManagerImpl mgr, PacketContext pctx,
1008 throws DropFlowException, RedirectFlowException {
1009 // Note that this call always returns `pctx'.
1010 inFlowFilters.evaluate(mgr, pctx, vid);
1014 * Evaluate flow filters for outgoing packet configured in this virtual
1017 * @param mgr VTN Manager service.
1018 * @param pctx The context of the received packet.
1019 * @param vid A VLAN ID to be used for packet matching.
1020 * A VLAN ID configured in the given packet is used if a
1021 * negative value is specified.
1022 * @param bridge Never used.
1023 * @return A {@link PacketContext} to be used for transmitting packet.
1024 * @throws DropFlowException
1025 * The given packet was discarded by a flow filter.
1026 * @throws RedirectFlowException
1027 * The given packet was redirected by a flow filter.
1030 public final PacketContext filterPacket(VTNManagerImpl mgr,
1031 PacketContext pctx, short vid,
1032 PortBridge<?> bridge)
1033 throws DropFlowException, RedirectFlowException {
1034 return outFlowFilters.evaluate(mgr, pctx, vid);
1037 // AbstractInterface
1040 * Initialize virtual interface path for this instance.
1042 * @param parent The parent node that contains this interface.
1043 * @param name The name of this interface.
1046 void setPath(AbstractBridge parent, String name) {
1047 super.setPath(parent, name);
1049 // Initialize parent path for flow filter.
1050 inFlowFilters.setParent(this);
1051 outFlowFilters.setParent(this);
1055 * Change enable/disable configuration of this interface.
1058 * This method assumes that the call of this method is synchronized
1059 * by the parent node.
1062 * @param mgr VTN Manager service.
1063 * @param ctx MD-SAL datastore transaction context.
1064 * @param db Virtual node state DB.
1065 * @param ist Current runtime state of this interface.
1066 * @param enabled {@code true} is passed if this interface has been
1068 * {@code false} is passed if this interface has been
1070 * @return New state of this interface.
1073 protected final VnodeState changeEnableState(
1074 VTNManagerImpl mgr, TxContext ctx,
1075 ConcurrentMap<VTenantPath, Object> db, VInterfaceState ist,
1079 // Determine new state by the state of mapped port.
1080 if (portMapConfig == null) {
1081 state = VnodeState.UNKNOWN;
1083 InventoryReader reader = ctx.getInventoryReader();
1085 state = getNewState(reader, ist);
1086 } catch (Exception e) {
1087 mgr.logException(getLogger(), getPath(), e);
1088 state = VnodeState.UNKNOWN;
1092 // State of disabled interface must be DOWN.
1093 state = VnodeState.DOWN;
1096 ist.setState(state);
1097 if (ist.isDirty()) {
1098 PortMapConfig pmconf = portMapConfig;
1099 if (pmconf != null) {
1100 // Invalidate all cached data added by the port mapping.
1101 NodeConnector mapped = ist.getMappedPort();
1102 short vlan = pmconf.getVlan();
1103 flushCache(mgr, mapped, vlan);
1105 db.put((VNodePath)getInterfacePath(), ist);
1112 * Invoked when this interface is going to be resuming from the
1113 * configuration file.
1115 * @param mgr VTN Manager service.
1116 * @param db Virtual node state DB.
1117 * @param ctx A runtime context for MD-SAL datastore transaction task.
1118 * @param ist Current state of this interface.
1119 * @return New state of this interface.
1122 protected final VnodeState resuming(VTNManagerImpl mgr,
1123 ConcurrentMap<VTenantPath, Object> db,
1124 TxContext ctx, VInterfaceState ist) {
1125 PortMapConfig pmconf = portMapConfig;
1126 if (pmconf == null) {
1127 return VnodeState.UNKNOWN;
1130 NodeConnector mapped = ist.getMappedPort();
1131 if (mapped == null) {
1132 // Try to establish port mapping.
1133 Node node = pmconf.getNode();
1134 InventoryReader reader = ctx.getInventoryReader();
1135 SwitchPort port = pmconf.getPort();
1137 SalPort sport = reader.findPort(node, port);
1138 if (sport != null) {
1139 mapPort(mgr, db, ist, sport, true);
1142 return getNewState(reader, ist);
1143 } catch (Exception e) {
1144 mgr.logException(getLogger(), getPath(), e);
1148 return VnodeState.UNKNOWN;
1152 * Invoked when this interface is going to be destroyed.
1154 * @param mgr VTN Manager service.
1155 * @param db Virtual node state DB.
1156 * @param ist Current state of this interface.
1157 * @param retain {@code true} means that the parent node will be retained.
1158 * {@code false} means that the parent node is being
1161 protected final void destroying(VTNManagerImpl mgr,
1162 ConcurrentMap<VTenantPath, Object> db,
1163 VInterfaceState ist, boolean retain) {
1164 if (retain && !(inFlowFilters.isEmpty() && outFlowFilters.isEmpty())) {
1165 // REVISIT: Select flow entries affected by obsolete flow filters.
1166 VTNThreadData.removeFlows(mgr, getTenantName());
1169 PortMapConfig pmconf = portMapConfig;
1170 if (pmconf != null) {
1171 // Destroy port mapping.
1172 NodeConnector mapped = ist.getMappedPort();
1173 PortMap pmap = new PortMap(pmconf, mapped);
1174 if (mapped != null) {
1175 unmapPort(mgr, db, ist, false, retain);
1177 PortMapEvent.removed(mgr, getInterfacePath(), pmap, false);
1182 * Notify the listener of current configuration.
1184 * @param mgr VTN Manager service.
1185 * @param listener VTN manager listener service.
1188 final void notifyConfiguration(VTNManagerImpl mgr,
1189 IVTNManagerAware listener) {
1190 super.notifyConfiguration(mgr, listener);
1192 PortMapConfig pmconf = portMapConfig;
1193 if (pmconf != null) {
1194 VInterfaceState ist = getIfState(mgr);
1195 NodeConnector mapped = ist.getMappedPort();
1196 PortMap pmap = new PortMap(pmconf, mapped);
1197 mgr.notifyChange(listener, getInterfacePath(), pmap,