Charles Chan
Committed by Gerrit Code Review

CORD-512 Support vSG <-> vRouter default route

- Support multiple subnets per port. getIpPort() will only return the first non-/32 and non-/0 subnet
    /32 is used as vSG subnet
    /0 is used as default gateway
- Support multiple L3 unicast group on a single port
    Change the way to generate the group ID and group key
- Special case for 0.0.0.0 host. Push a /0 to IP table instead of /32
- Implement vRouterConfig
    Put VR MAC to TMAC table of all leaves when config added
        When processEthDst see PortNumber.ANY in key, match ETH_DST only
- For OFDPA, wipe existing instruction before sending to controller
    So packet that misses L3 unicast table won't be sent to controller twice
- For SpringOpenTTP, pop VLAN before sending to controller
- Move several constant definitions to SegmentRoutingService
- Add minimum priority for IP rules such that /0 won't collide with zero priority default rules
- Update the config sample
    Use VLAN=-1 for hosts
    Add example for default route

Change-Id: Id751697ce36a7e5c13b3859350ff21b585c38525
Showing 21 changed files with 827 additions and 144 deletions
...@@ -97,6 +97,14 @@ ...@@ -97,6 +97,14 @@
97 <artifactId>onlab-junit</artifactId> 97 <artifactId>onlab-junit</artifactId>
98 <scope>test</scope> 98 <scope>test</scope>
99 </dependency> 99 </dependency>
100 +
101 + <dependency>
102 + <groupId>org.onosproject</groupId>
103 + <artifactId>onos-api</artifactId>
104 + <version>${project.version}</version>
105 + <scope>test</scope>
106 + <classifier>tests</classifier>
107 + </dependency>
100 </dependencies> 108 </dependencies>
101 109
102 <build> 110 <build>
......
...@@ -168,7 +168,7 @@ public class IcmpHandler { ...@@ -168,7 +168,7 @@ public class IcmpHandler {
168 treatment, ByteBuffer.wrap(payload.serialize())); 168 treatment, ByteBuffer.wrap(payload.serialize()));
169 srManager.packetService.emit(packet); 169 srManager.packetService.emit(packet);
170 } else { 170 } else {
171 - log.warn("Send a MPLS packet as a ICMP response"); 171 + log.info("Send a MPLS packet as a ICMP response");
172 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 172 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
173 .setOutput(outport.port()) 173 .setOutput(outport.port())
174 .build(); 174 .build();
......
1 +package org.onosproject.segmentrouting;
2 +
3 +import com.google.common.collect.ImmutableSet;
4 +import org.onlab.packet.MacAddress;
5 +import org.onosproject.net.DeviceId;
6 +import org.onosproject.net.PortNumber;
7 +import org.onosproject.net.config.NetworkConfigEvent;
8 +import org.onosproject.net.device.DeviceService;
9 +import org.onosproject.net.flow.criteria.Criteria;
10 +import org.onosproject.net.flowobjective.DefaultFilteringObjective;
11 +import org.onosproject.net.flowobjective.FilteringObjective;
12 +import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
13 +import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
14 +import org.slf4j.Logger;
15 +import org.slf4j.LoggerFactory;
16 +
17 +import java.util.HashSet;
18 +import java.util.Set;
19 +
20 +/**
21 + * Handles network config events.
22 + */
23 +public class NetworkConfigEventHandler {
24 + private static final Logger log = LoggerFactory.getLogger(NetworkConfigEventHandler.class);
25 + private final SegmentRoutingManager srManager;
26 + private final DeviceService deviceService;
27 +
28 + /**
29 + * Constructs Network Config Event Handler.
30 + *
31 + * @param srManager instance of {@link SegmentRoutingManager}
32 + */
33 + public NetworkConfigEventHandler(SegmentRoutingManager srManager) {
34 + this.srManager = srManager;
35 + this.deviceService = srManager.deviceService;
36 + }
37 +
38 + /**
39 + * Processes vRouter config added event.
40 + *
41 + * @param event network config added event
42 + */
43 + protected void processVRouterConfigAdded(NetworkConfigEvent event) {
44 + log.info("Processing vRouter CONFIG_ADDED");
45 + SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get();
46 + deviceService.getAvailableDevices().forEach(device -> {
47 + populateVRouter(device.id(), getMacAddresses(config));
48 + });
49 + }
50 +
51 + /**
52 + * Processes vRouter config updated event.
53 + *
54 + * @param event network config updated event
55 + */
56 + protected void processVRouterConfigUpdated(NetworkConfigEvent event) {
57 + log.info("Processing vRouter CONFIG_UPDATED");
58 + SegmentRoutingAppConfig config = (SegmentRoutingAppConfig) event.config().get();
59 + SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get();
60 + deviceService.getAvailableDevices().forEach(device -> {
61 + Set<MacAddress> macAddresses = getMacAddresses(config);
62 + Set<MacAddress> prevMacAddresses = getMacAddresses(prevConfig);
63 + // Avoid removing and re-adding unchanged MAC addresses since
64 + // FlowObjective does not guarantee the execution order.
65 + Set<MacAddress> sameMacAddresses = new HashSet<>(macAddresses);
66 + sameMacAddresses.retainAll(prevMacAddresses);
67 + macAddresses.removeAll(sameMacAddresses);
68 + prevMacAddresses.removeAll(sameMacAddresses);
69 +
70 + revokeVRouter(device.id(), prevMacAddresses);
71 + populateVRouter(device.id(), macAddresses);
72 + });
73 +
74 + }
75 +
76 + /**
77 + * Processes vRouter config removed event.
78 + *
79 + * @param event network config removed event
80 + */
81 + protected void processVRouterConfigRemoved(NetworkConfigEvent event) {
82 + log.info("Processing vRouter CONFIG_REMOVED");
83 + SegmentRoutingAppConfig prevConfig = (SegmentRoutingAppConfig) event.prevConfig().get();
84 + deviceService.getAvailableDevices().forEach(device -> {
85 + revokeVRouter(device.id(), getMacAddresses(prevConfig));
86 + });
87 + }
88 +
89 + /**
90 + * Populates initial vRouter rules.
91 + *
92 + * @param deviceId device ID
93 + */
94 + public void initVRouters(DeviceId deviceId) {
95 + SegmentRoutingAppConfig config =
96 + srManager.cfgService.getConfig(srManager.appId, SegmentRoutingAppConfig.class);
97 + populateVRouter(deviceId, getMacAddresses(config));
98 + }
99 +
100 + private void populateVRouter(DeviceId deviceId, Set<MacAddress> pendingAdd) {
101 + if (!isEdge(deviceId)) {
102 + return;
103 + }
104 + getVRouterFlowObjBuilders(pendingAdd).forEach(foBuilder -> {
105 + srManager.flowObjectiveService.
106 + filter(deviceId, foBuilder.add(new SRObjectiveContext(deviceId,
107 + SRObjectiveContext.ObjectiveType.FILTER)));
108 + });
109 + }
110 +
111 + private void revokeVRouter(DeviceId deviceId, Set<MacAddress> pendingRemove) {
112 + if (!isEdge(deviceId)) {
113 + return;
114 + }
115 + getVRouterFlowObjBuilders(pendingRemove).forEach(foBuilder -> {
116 + srManager.flowObjectiveService.
117 + filter(deviceId, foBuilder.remove(new SRObjectiveContext(deviceId,
118 + SRObjectiveContext.ObjectiveType.FILTER)));
119 + });
120 + }
121 +
122 + private Set<FilteringObjective.Builder> getVRouterFlowObjBuilders(Set<MacAddress> macAddresses) {
123 + ImmutableSet.Builder<FilteringObjective.Builder> setBuilder = ImmutableSet.builder();
124 + macAddresses.forEach(macAddress -> {
125 + FilteringObjective.Builder fobuilder = DefaultFilteringObjective.builder();
126 + fobuilder.withKey(Criteria.matchInPort(PortNumber.ANY))
127 + .addCondition(Criteria.matchEthDst(macAddress))
128 + .permit()
129 + .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
130 + .fromApp(srManager.appId);
131 + setBuilder.add(fobuilder);
132 + });
133 + return setBuilder.build();
134 + }
135 +
136 + private Set<MacAddress> getMacAddresses(SegmentRoutingAppConfig config) {
137 + if (config == null) {
138 + return ImmutableSet.of();
139 + }
140 +
141 + HashSet<MacAddress> macAddresses = new HashSet<>();
142 + config.vRouterMacs().forEach(mac -> {
143 + macAddresses.add(mac);
144 + });
145 + return ImmutableSet.copyOf(macAddresses);
146 + }
147 +
148 + private boolean isEdge(DeviceId deviceId) {
149 + try {
150 + if (srManager.deviceConfiguration.isEdgeDevice(deviceId)) {
151 + return true;
152 + }
153 + } catch (DeviceConfigNotFoundException e) { }
154 + return false;
155 + }
156 +}
...@@ -39,11 +39,8 @@ import org.onosproject.net.flowobjective.DefaultFilteringObjective; ...@@ -39,11 +39,8 @@ import org.onosproject.net.flowobjective.DefaultFilteringObjective;
39 import org.onosproject.net.flowobjective.DefaultForwardingObjective; 39 import org.onosproject.net.flowobjective.DefaultForwardingObjective;
40 import org.onosproject.net.flowobjective.FilteringObjective; 40 import org.onosproject.net.flowobjective.FilteringObjective;
41 import org.onosproject.net.flowobjective.ForwardingObjective; 41 import org.onosproject.net.flowobjective.ForwardingObjective;
42 -import org.onosproject.net.flowobjective.Objective;
43 -import org.onosproject.net.flowobjective.ObjectiveError;
44 import org.onosproject.net.flowobjective.ForwardingObjective.Builder; 42 import org.onosproject.net.flowobjective.ForwardingObjective.Builder;
45 import org.onosproject.net.flowobjective.ForwardingObjective.Flag; 43 import org.onosproject.net.flowobjective.ForwardingObjective.Flag;
46 -import org.onosproject.net.flowobjective.ObjectiveContext;
47 import org.slf4j.Logger; 44 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory; 45 import org.slf4j.LoggerFactory;
49 46
...@@ -67,14 +64,6 @@ public class RoutingRulePopulator { ...@@ -67,14 +64,6 @@ public class RoutingRulePopulator {
67 private SegmentRoutingManager srManager; 64 private SegmentRoutingManager srManager;
68 private DeviceConfiguration config; 65 private DeviceConfiguration config;
69 66
70 - private static final int HIGHEST_PRIORITY = 0xffff;
71 - //
72 - private static final int XCONNECT_PRIORITY = 1000;
73 - private static final int DEFAULT_PRIORITY = 100;
74 - private static final int FLOOD_PRIORITY = 5;
75 - private static final long OFPP_MAX = 0xffffff00L;
76 -
77 -
78 /** 67 /**
79 * Creates a RoutingRulePopulator object. 68 * Creates a RoutingRulePopulator object.
80 * 69 *
...@@ -160,12 +149,21 @@ public class RoutingRulePopulator { ...@@ -160,12 +149,21 @@ public class RoutingRulePopulator {
160 throws DeviceConfigNotFoundException { 149 throws DeviceConfigNotFoundException {
161 MacAddress deviceMac; 150 MacAddress deviceMac;
162 deviceMac = config.getDeviceMac(deviceId); 151 deviceMac = config.getDeviceMac(deviceId);
152 + int priority;
163 153
164 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); 154 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
165 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder(); 155 TrafficTreatment.Builder tbuilder = DefaultTrafficTreatment.builder();
166 156
167 sbuilder.matchEthType(Ethernet.TYPE_IPV4); 157 sbuilder.matchEthType(Ethernet.TYPE_IPV4);
168 - sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH)); 158 + // Special case for default route
159 + if (hostIp.isZero()) {
160 + sbuilder.matchIPDst(IpPrefix.valueOf(hostIp, 0));
161 + priority = SegmentRoutingService.MIN_IP_PRIORITY;
162 + } else {
163 + Ip4Prefix hostIpPrefix = Ip4Prefix.valueOf(hostIp, IpPrefix.MAX_INET_MASK_LENGTH);
164 + sbuilder.matchIPDst(hostIpPrefix);
165 + priority = getPriorityFromPrefix(hostIpPrefix);
166 + }
169 TrafficSelector selector = sbuilder.build(); 167 TrafficSelector selector = sbuilder.build();
170 168
171 tbuilder.deferred() 169 tbuilder.deferred()
...@@ -192,7 +190,8 @@ public class RoutingRulePopulator { ...@@ -192,7 +190,8 @@ public class RoutingRulePopulator {
192 .withSelector(selector) 190 .withSelector(selector)
193 .nextStep(portNextObjId) 191 .nextStep(portNextObjId)
194 .fromApp(srManager.appId).makePermanent() 192 .fromApp(srManager.appId).makePermanent()
195 - .withPriority(DEFAULT_PRIORITY).withFlag(ForwardingObjective.Flag.SPECIFIC); 193 + .withPriority(priority)
194 + .withFlag(ForwardingObjective.Flag.SPECIFIC);
196 } 195 }
197 196
198 /** 197 /**
...@@ -277,7 +276,7 @@ public class RoutingRulePopulator { ...@@ -277,7 +276,7 @@ public class RoutingRulePopulator {
277 .makePermanent() 276 .makePermanent()
278 .nextStep(nextId) 277 .nextStep(nextId)
279 .withSelector(selector) 278 .withSelector(selector)
280 - .withPriority(2000 * ipPrefix.prefixLength()) 279 + .withPriority(getPriorityFromPrefix(ipPrefix))
281 .withFlag(ForwardingObjective.Flag.SPECIFIC); 280 .withFlag(ForwardingObjective.Flag.SPECIFIC);
282 if (treatment != null) { 281 if (treatment != null) {
283 fwdBuilder.withTreatment(treatment); 282 fwdBuilder.withTreatment(treatment);
...@@ -386,7 +385,7 @@ public class RoutingRulePopulator { ...@@ -386,7 +385,7 @@ public class RoutingRulePopulator {
386 for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) { 385 for (ForwardingObjective.Builder fwdObjBuilder : fwdObjBuilders) {
387 ((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId) 386 ((Builder) ((Builder) fwdObjBuilder.fromApp(srManager.appId)
388 .makePermanent()).withSelector(selector) 387 .makePermanent()).withSelector(selector)
389 - .withPriority(DEFAULT_PRIORITY)) 388 + .withPriority(SegmentRoutingService.DEFAULT_PRIORITY))
390 .withFlag(ForwardingObjective.Flag.SPECIFIC); 389 .withFlag(ForwardingObjective.Flag.SPECIFIC);
391 srManager.flowObjectiveService. 390 srManager.flowObjectiveService.
392 forward(deviceId, 391 forward(deviceId,
...@@ -472,7 +471,9 @@ public class RoutingRulePopulator { ...@@ -472,7 +471,9 @@ public class RoutingRulePopulator {
472 } 471 }
473 472
474 for (Port port : srManager.deviceService.getPorts(deviceId)) { 473 for (Port port : srManager.deviceService.getPorts(deviceId)) {
475 - if (port.number().toLong() > 0 && port.number().toLong() < OFPP_MAX) { 474 + if (port.number().toLong() > 0 &&
475 + port.number().toLong() < SegmentRoutingService.OFPP_MAX &&
476 + port.isEnabled()) {
476 Ip4Prefix portSubnet = config.getPortSubnet(deviceId, port.number()); 477 Ip4Prefix portSubnet = config.getPortSubnet(deviceId, port.number());
477 VlanId assignedVlan = (portSubnet == null) 478 VlanId assignedVlan = (portSubnet == null)
478 ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET) 479 ? VlanId.vlanId(SegmentRoutingManager.ASSIGNED_VLAN_NO_SUBNET)
...@@ -482,7 +483,7 @@ public class RoutingRulePopulator { ...@@ -482,7 +483,7 @@ public class RoutingRulePopulator {
482 fob.withKey(Criteria.matchInPort(port.number())) 483 fob.withKey(Criteria.matchInPort(port.number()))
483 .addCondition(Criteria.matchEthDst(deviceMac)) 484 .addCondition(Criteria.matchEthDst(deviceMac))
484 .addCondition(Criteria.matchVlanId(VlanId.NONE)) 485 .addCondition(Criteria.matchVlanId(VlanId.NONE))
485 - .withPriority(DEFAULT_PRIORITY); 486 + .withPriority(SegmentRoutingService.DEFAULT_PRIORITY);
486 // vlan assignment is valid only if this instance is master 487 // vlan assignment is valid only if this instance is master
487 if (srManager.mastershipService.isLocalMaster(deviceId)) { 488 if (srManager.mastershipService.isLocalMaster(deviceId)) {
488 TrafficTreatment tt = DefaultTrafficTreatment.builder() 489 TrafficTreatment tt = DefaultTrafficTreatment.builder()
...@@ -520,7 +521,7 @@ public class RoutingRulePopulator { ...@@ -520,7 +521,7 @@ public class RoutingRulePopulator {
520 return; 521 return;
521 } 522 }
522 ForwardingObjective.Builder puntIp = DefaultForwardingObjective.builder(); 523 ForwardingObjective.Builder puntIp = DefaultForwardingObjective.builder();
523 - Set<Ip4Address> allIps = new HashSet<Ip4Address>(config.getPortIPs(deviceId)); 524 + Set<Ip4Address> allIps = new HashSet<>(config.getPortIPs(deviceId));
524 allIps.add(routerIp); 525 allIps.add(routerIp);
525 for (Ip4Address ipaddr : allIps) { 526 for (Ip4Address ipaddr : allIps) {
526 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder(); 527 TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
...@@ -532,7 +533,7 @@ public class RoutingRulePopulator { ...@@ -532,7 +533,7 @@ public class RoutingRulePopulator {
532 puntIp.withSelector(sbuilder.build()); 533 puntIp.withSelector(sbuilder.build());
533 puntIp.withTreatment(tbuilder.build()); 534 puntIp.withTreatment(tbuilder.build());
534 puntIp.withFlag(Flag.VERSATILE) 535 puntIp.withFlag(Flag.VERSATILE)
535 - .withPriority(HIGHEST_PRIORITY) 536 + .withPriority(SegmentRoutingService.HIGHEST_PRIORITY)
536 .makePermanent() 537 .makePermanent()
537 .fromApp(srManager.appId); 538 .fromApp(srManager.appId);
538 log.debug("Installing forwarding objective to punt port IP addresses"); 539 log.debug("Installing forwarding objective to punt port IP addresses");
...@@ -576,7 +577,7 @@ public class RoutingRulePopulator { ...@@ -576,7 +577,7 @@ public class RoutingRulePopulator {
576 fob.withFlag(Flag.SPECIFIC) 577 fob.withFlag(Flag.SPECIFIC)
577 .withSelector(sbuilder.build()) 578 .withSelector(sbuilder.build())
578 .nextStep(nextId) 579 .nextStep(nextId)
579 - .withPriority(FLOOD_PRIORITY) 580 + .withPriority(SegmentRoutingService.FLOOD_PRIORITY)
580 .fromApp(srManager.appId) 581 .fromApp(srManager.appId)
581 .makePermanent(); 582 .makePermanent();
582 583
...@@ -611,7 +612,7 @@ public class RoutingRulePopulator { ...@@ -611,7 +612,7 @@ public class RoutingRulePopulator {
611 fob.withKey(Criteria.matchInPort(connectPoint.port())) 612 fob.withKey(Criteria.matchInPort(connectPoint.port()))
612 .addCondition(Criteria.matchVlanId(vlanId)) 613 .addCondition(Criteria.matchVlanId(vlanId))
613 .addCondition(Criteria.matchEthDst(MacAddress.NONE)) 614 .addCondition(Criteria.matchEthDst(MacAddress.NONE))
614 - .withPriority(XCONNECT_PRIORITY); 615 + .withPriority(SegmentRoutingService.XCONNECT_PRIORITY);
615 616
616 fob.permit().fromApp(srManager.appId); 617 fob.permit().fromApp(srManager.appId);
617 srManager.flowObjectiveService 618 srManager.flowObjectiveService
...@@ -657,7 +658,7 @@ public class RoutingRulePopulator { ...@@ -657,7 +658,7 @@ public class RoutingRulePopulator {
657 fob.withFlag(Flag.SPECIFIC) 658 fob.withFlag(Flag.SPECIFIC)
658 .withSelector(sbuilder.build()) 659 .withSelector(sbuilder.build())
659 .nextStep(nextId) 660 .nextStep(nextId)
660 - .withPriority(DEFAULT_PRIORITY) 661 + .withPriority(SegmentRoutingService.DEFAULT_PRIORITY)
661 .fromApp(srManager.appId) 662 .fromApp(srManager.appId)
662 .makePermanent(); 663 .makePermanent();
663 664
...@@ -671,29 +672,9 @@ public class RoutingRulePopulator { ...@@ -671,29 +672,9 @@ public class RoutingRulePopulator {
671 }); 672 });
672 } 673 }
673 674
674 - private static class SRObjectiveContext implements ObjectiveContext { 675 + private int getPriorityFromPrefix(IpPrefix prefix) {
675 - enum ObjectiveType { 676 + return (prefix.isIp4()) ?
676 - FILTER, 677 + 2000 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY :
677 - FORWARDING 678 + 500 * prefix.prefixLength() + SegmentRoutingService.MIN_IP_PRIORITY;
678 - }
679 - final DeviceId deviceId;
680 - final ObjectiveType type;
681 -
682 - SRObjectiveContext(DeviceId deviceId, ObjectiveType type) {
683 - this.deviceId = deviceId;
684 - this.type = type;
685 - }
686 - @Override
687 - public void onSuccess(Objective objective) {
688 - log.debug("{} objective operation successful in device {}",
689 - type.name(), deviceId);
690 - }
691 -
692 - @Override
693 - public void onError(Objective objective, ObjectiveError error) {
694 - log.warn("{} objective {} operation failed with error: {} in device {}",
695 - type.name(), objective, error, deviceId);
696 - }
697 } 679 }
698 -
699 } 680 }
......
1 +package org.onosproject.segmentrouting;
2 +
3 +import org.onosproject.net.DeviceId;
4 +import org.onosproject.net.flowobjective.Objective;
5 +import org.onosproject.net.flowobjective.ObjectiveContext;
6 +import org.onosproject.net.flowobjective.ObjectiveError;
7 +import org.slf4j.Logger;
8 +import org.slf4j.LoggerFactory;
9 +
10 +/**
11 + * Segment Routing Flow Objective Context.
12 + */
13 +public class SRObjectiveContext implements ObjectiveContext {
14 + enum ObjectiveType {
15 + FILTER,
16 + FORWARDING
17 + }
18 + private final DeviceId deviceId;
19 + private final ObjectiveType type;
20 +
21 + private static final Logger log = LoggerFactory
22 + .getLogger(SegmentRoutingManager.class);
23 +
24 + SRObjectiveContext(DeviceId deviceId, ObjectiveType type) {
25 + this.deviceId = deviceId;
26 + this.type = type;
27 + }
28 + @Override
29 + public void onSuccess(Objective objective) {
30 + log.debug("{} objective operation successful in device {}",
31 + type.name(), deviceId);
32 + }
33 +
34 + @Override
35 + public void onError(Objective objective, ObjectiveError error) {
36 + log.warn("{} objective {} operation failed with error: {} in device {}",
37 + type.name(), objective, error, deviceId);
38 + }
39 +}
40 +
...@@ -54,7 +54,8 @@ import org.onosproject.net.host.HostListener; ...@@ -54,7 +54,8 @@ import org.onosproject.net.host.HostListener;
54 import org.onosproject.net.packet.PacketPriority; 54 import org.onosproject.net.packet.PacketPriority;
55 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException; 55 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
56 import org.onosproject.segmentrouting.config.DeviceConfiguration; 56 import org.onosproject.segmentrouting.config.DeviceConfiguration;
57 -import org.onosproject.segmentrouting.config.SegmentRoutingConfig; 57 +import org.onosproject.segmentrouting.config.SegmentRoutingDeviceConfig;
58 +import org.onosproject.segmentrouting.config.SegmentRoutingAppConfig;
58 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler; 59 import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
59 import org.onosproject.segmentrouting.grouphandler.NeighborSet; 60 import org.onosproject.segmentrouting.grouphandler.NeighborSet;
60 import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey; 61 import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
...@@ -130,6 +131,12 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -130,6 +131,12 @@ public class SegmentRoutingManager implements SegmentRoutingService {
130 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 131 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
131 protected MastershipService mastershipService; 132 protected MastershipService mastershipService;
132 133
134 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
135 + protected StorageService storageService;
136 +
137 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
138 + protected NetworkConfigRegistry cfgService;
139 +
133 protected ArpHandler arpHandler = null; 140 protected ArpHandler arpHandler = null;
134 protected IcmpHandler icmpHandler = null; 141 protected IcmpHandler icmpHandler = null;
135 protected IpHandler ipHandler = null; 142 protected IpHandler ipHandler = null;
...@@ -143,7 +150,9 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -143,7 +150,9 @@ public class SegmentRoutingManager implements SegmentRoutingService {
143 private InternalPacketProcessor processor = null; 150 private InternalPacketProcessor processor = null;
144 private InternalLinkListener linkListener = null; 151 private InternalLinkListener linkListener = null;
145 private InternalDeviceListener deviceListener = null; 152 private InternalDeviceListener deviceListener = null;
153 + private NetworkConfigEventHandler netcfgHandler = null;
146 private InternalEventHandler eventHandler = new InternalEventHandler(); 154 private InternalEventHandler eventHandler = new InternalEventHandler();
155 + private final InternalHostListener hostListener = new InternalHostListener();
147 156
148 private ScheduledExecutorService executorService = Executors 157 private ScheduledExecutorService executorService = Executors
149 .newScheduledThreadPool(1); 158 .newScheduledThreadPool(1);
...@@ -181,27 +190,28 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -181,27 +190,28 @@ public class SegmentRoutingManager implements SegmentRoutingService {
181 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null; 190 private EventuallyConsistentMap<String, Tunnel> tunnelStore = null;
182 private EventuallyConsistentMap<String, Policy> policyStore = null; 191 private EventuallyConsistentMap<String, Policy> policyStore = null;
183 192
184 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
185 - protected StorageService storageService;
186 -
187 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
188 - protected NetworkConfigRegistry cfgService;
189 -
190 private final InternalConfigListener cfgListener = 193 private final InternalConfigListener cfgListener =
191 new InternalConfigListener(this); 194 new InternalConfigListener(this);
192 195
193 - @SuppressWarnings({ "unchecked", "rawtypes" }) 196 + private final ConfigFactory<DeviceId, SegmentRoutingDeviceConfig> cfgDeviceFactory =
194 - private final ConfigFactory cfgFactory = 197 + new ConfigFactory<DeviceId, SegmentRoutingDeviceConfig>(SubjectFactories.DEVICE_SUBJECT_FACTORY,
195 - new ConfigFactory(SubjectFactories.DEVICE_SUBJECT_FACTORY, 198 + SegmentRoutingDeviceConfig.class,
196 - SegmentRoutingConfig.class,
197 "segmentrouting") { 199 "segmentrouting") {
198 @Override 200 @Override
199 - public SegmentRoutingConfig createConfig() { 201 + public SegmentRoutingDeviceConfig createConfig() {
200 - return new SegmentRoutingConfig(); 202 + return new SegmentRoutingDeviceConfig();
201 } 203 }
202 }; 204 };
203 205
204 - private final InternalHostListener hostListener = new InternalHostListener(); 206 + private final ConfigFactory<ApplicationId, SegmentRoutingAppConfig> cfgAppFactory =
207 + new ConfigFactory<ApplicationId, SegmentRoutingAppConfig>(SubjectFactories.APP_SUBJECT_FACTORY,
208 + SegmentRoutingAppConfig.class,
209 + "segmentrouting") {
210 + @Override
211 + public SegmentRoutingAppConfig createConfig() {
212 + return new SegmentRoutingAppConfig();
213 + }
214 + };
205 215
206 private Object threadSchedulerLock = new Object(); 216 private Object threadSchedulerLock = new Object();
207 private static int numOfEventsQueued = 0; 217 private static int numOfEventsQueued = 0;
...@@ -223,7 +233,7 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -223,7 +233,7 @@ public class SegmentRoutingManager implements SegmentRoutingService {
223 @Activate 233 @Activate
224 protected void activate() { 234 protected void activate() {
225 appId = coreService 235 appId = coreService
226 - .registerApplication("org.onosproject.segmentrouting"); 236 + .registerApplication(SR_APP_ID);
227 237
228 kryoBuilder = new KryoNamespace.Builder() 238 kryoBuilder = new KryoNamespace.Builder()
229 .register(NeighborSetNextObjectiveStoreKey.class, 239 .register(NeighborSetNextObjectiveStoreKey.class,
...@@ -309,14 +319,15 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -309,14 +319,15 @@ public class SegmentRoutingManager implements SegmentRoutingService {
309 .build(); 319 .build();
310 320
311 cfgService.addListener(cfgListener); 321 cfgService.addListener(cfgListener);
312 - cfgService.registerConfigFactory(cfgFactory); 322 + cfgService.registerConfigFactory(cfgDeviceFactory);
313 - 323 + cfgService.registerConfigFactory(cfgAppFactory);
314 - hostService.addListener(hostListener);
315 324
316 processor = new InternalPacketProcessor(); 325 processor = new InternalPacketProcessor();
317 linkListener = new InternalLinkListener(); 326 linkListener = new InternalLinkListener();
318 deviceListener = new InternalDeviceListener(); 327 deviceListener = new InternalDeviceListener();
328 + netcfgHandler = new NetworkConfigEventHandler(this);
319 329
330 + hostService.addListener(hostListener);
320 packetService.addProcessor(processor, PacketProcessor.director(2)); 331 packetService.addProcessor(processor, PacketProcessor.director(2));
321 linkService.addListener(linkListener); 332 linkService.addListener(linkListener);
322 deviceService.addListener(deviceListener); 333 deviceService.addListener(deviceListener);
...@@ -334,7 +345,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -334,7 +345,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
334 @Deactivate 345 @Deactivate
335 protected void deactivate() { 346 protected void deactivate() {
336 cfgService.removeListener(cfgListener); 347 cfgService.removeListener(cfgListener);
337 - cfgService.unregisterConfigFactory(cfgFactory); 348 + cfgService.unregisterConfigFactory(cfgDeviceFactory);
349 + cfgService.unregisterConfigFactory(cfgAppFactory);
338 350
339 // Withdraw ARP packet-in 351 // Withdraw ARP packet-in
340 TrafficSelector.Builder selector = DefaultTrafficSelector.builder(); 352 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
...@@ -456,10 +468,17 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -456,10 +468,17 @@ public class SegmentRoutingManager implements SegmentRoutingService {
456 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1); 468 nextAssignedVlan = (short) (Collections.min(assignedVlans) - 1);
457 } 469 }
458 for (Ip4Prefix unsub : unassignedSubnets) { 470 for (Ip4Prefix unsub : unassignedSubnets) {
459 - subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub), 471 + // Special case for default route. Assign default VLAN ID to /32 and /0 subnets
460 - VlanId.vlanId(nextAssignedVlan--)); 472 + if (unsub.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH ||
461 - log.info("Assigned vlan: {} to subnet: {} on device: {}", 473 + unsub.prefixLength() == 0) {
462 - nextAssignedVlan + 1, unsub, deviceId); 474 + subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
475 + VlanId.vlanId(ASSIGNED_VLAN_NO_SUBNET));
476 + } else {
477 + subnetVidStore.put(new SubnetAssignedVidStoreKey(deviceId, unsub),
478 + VlanId.vlanId(nextAssignedVlan--));
479 + log.info("Assigned vlan: {} to subnet: {} on device: {}",
480 + nextAssignedVlan + 1, unsub, deviceId);
481 + }
463 } 482 }
464 483
465 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet)); 484 return subnetVidStore.get(new SubnetAssignedVidStoreKey(deviceId, subnet));
...@@ -766,6 +785,8 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -766,6 +785,8 @@ public class SegmentRoutingManager implements SegmentRoutingService {
766 groupHandler.createGroupsForXConnect(device.id()); 785 groupHandler.createGroupsForXConnect(device.id());
767 routingRulePopulator.populateXConnectBroadcastRule(device.id()); 786 routingRulePopulator.populateXConnectBroadcastRule(device.id());
768 } 787 }
788 +
789 + netcfgHandler.initVRouters(device.id());
769 } 790 }
770 791
771 private void processPortRemoved(Device device, Port port) { 792 private void processPortRemoved(Device device, Port port) {
...@@ -851,14 +872,33 @@ public class SegmentRoutingManager implements SegmentRoutingService { ...@@ -851,14 +872,33 @@ public class SegmentRoutingManager implements SegmentRoutingService {
851 872
852 @Override 873 @Override
853 public void event(NetworkConfigEvent event) { 874 public void event(NetworkConfigEvent event) {
854 - if (event.configClass().equals(SegmentRoutingConfig.class)) { 875 + // TODO move this part to NetworkConfigEventHandler
855 - if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) { 876 + if (event.configClass().equals(SegmentRoutingDeviceConfig.class)) {
856 - log.info("Network configuration added."); 877 + switch (event.type()) {
857 - configureNetwork(); 878 + case CONFIG_ADDED:
879 + log.info("Segment Routing Config added.");
880 + configureNetwork();
881 + break;
882 + case CONFIG_UPDATED:
883 + log.info("Segment Routing Config updated.");
884 + // TODO support dynamic configuration
885 + break;
886 + default:
887 + break;
858 } 888 }
859 - if (event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) { 889 + } else if (event.configClass().equals(SegmentRoutingAppConfig.class)) {
860 - log.info("Network configuration updated."); 890 + switch (event.type()) {
861 - // TODO support dynamic configuration 891 + case CONFIG_ADDED:
892 + netcfgHandler.processVRouterConfigAdded(event);
893 + break;
894 + case CONFIG_UPDATED:
895 + netcfgHandler.processVRouterConfigUpdated(event);
896 + break;
897 + case CONFIG_REMOVED:
898 + netcfgHandler.processVRouterConfigRemoved(event);
899 + break;
900 + default:
901 + break;
862 } 902 }
863 } 903 }
864 } 904 }
......
...@@ -21,6 +21,40 @@ import java.util.List; ...@@ -21,6 +21,40 @@ import java.util.List;
21 * Segment Routing Service for REST API. 21 * Segment Routing Service for REST API.
22 */ 22 */
23 public interface SegmentRoutingService { 23 public interface SegmentRoutingService {
24 + /**
25 + * Segment Routing App ID.
26 + */
27 + String SR_APP_ID = "org.onosproject.segmentrouting";
28 +
29 + /**
30 + * Highest flow priority.
31 + */
32 + int HIGHEST_PRIORITY = 0xffff;
33 +
34 + /**
35 + * VLAN cross-connect priority.
36 + */
37 + int XCONNECT_PRIORITY = 1000;
38 +
39 + /**
40 + * Default flow priority.
41 + */
42 + int DEFAULT_PRIORITY = 100;
43 +
44 + /**
45 + * Minimum IP priority.
46 + *
47 + * Should > 0 such that priority of /0 will not conflict with lowest
48 + * priority default entries.
49 + */
50 + int MIN_IP_PRIORITY = 10;
51 +
52 + /**
53 + * Subnet flooding flow priority.
54 + */
55 + int FLOOD_PRIORITY = 5;
56 +
57 + long OFPP_MAX = 0xffffff00L;
24 58
25 /** 59 /**
26 * Returns all tunnels. 60 * Returns all tunnels.
......
...@@ -15,9 +15,12 @@ ...@@ -15,9 +15,12 @@
15 */ 15 */
16 package org.onosproject.segmentrouting.config; 16 package org.onosproject.segmentrouting.config;
17 17
18 +import com.google.common.collect.HashMultimap;
18 import com.google.common.collect.ImmutableSet; 19 import com.google.common.collect.ImmutableSet;
20 +import com.google.common.collect.SetMultimap;
19 import org.onlab.packet.Ip4Address; 21 import org.onlab.packet.Ip4Address;
20 import org.onlab.packet.Ip4Prefix; 22 import org.onlab.packet.Ip4Prefix;
23 +import org.onlab.packet.IpPrefix;
21 import org.onlab.packet.MacAddress; 24 import org.onlab.packet.MacAddress;
22 import org.onlab.packet.VlanId; 25 import org.onlab.packet.VlanId;
23 import org.onosproject.incubator.net.config.basics.ConfigException; 26 import org.onosproject.incubator.net.config.basics.ConfigException;
...@@ -37,6 +40,7 @@ import java.util.HashSet; ...@@ -37,6 +40,7 @@ import java.util.HashSet;
37 import java.util.LinkedList; 40 import java.util.LinkedList;
38 import java.util.List; 41 import java.util.List;
39 import java.util.Map; 42 import java.util.Map;
43 +import java.util.Optional;
40 import java.util.Set; 44 import java.util.Set;
41 import java.util.concurrent.ConcurrentHashMap; 45 import java.util.concurrent.ConcurrentHashMap;
42 46
...@@ -59,13 +63,13 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -59,13 +63,13 @@ public class DeviceConfiguration implements DeviceProperties {
59 Ip4Address ip; 63 Ip4Address ip;
60 MacAddress mac; 64 MacAddress mac;
61 boolean isEdge; 65 boolean isEdge;
62 - HashMap<PortNumber, Ip4Address> gatewayIps; 66 + Map<PortNumber, Ip4Address> gatewayIps;
63 - HashMap<PortNumber, Ip4Prefix> subnets; 67 + SetMultimap<PortNumber, Ip4Prefix> subnets;
64 Map<Integer, Set<Integer>> adjacencySids; 68 Map<Integer, Set<Integer>> adjacencySids;
65 69
66 public SegmentRouterInfo() { 70 public SegmentRouterInfo() {
67 gatewayIps = new HashMap<>(); 71 gatewayIps = new HashMap<>();
68 - subnets = new HashMap<>(); 72 + subnets = HashMultimap.create();
69 } 73 }
70 } 74 }
71 75
...@@ -78,10 +82,10 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -78,10 +82,10 @@ public class DeviceConfiguration implements DeviceProperties {
78 public DeviceConfiguration(NetworkConfigRegistry cfgService) { 82 public DeviceConfiguration(NetworkConfigRegistry cfgService) {
79 // Read config from device subject, excluding gatewayIps and subnets. 83 // Read config from device subject, excluding gatewayIps and subnets.
80 Set<DeviceId> deviceSubjects = 84 Set<DeviceId> deviceSubjects =
81 - cfgService.getSubjects(DeviceId.class, SegmentRoutingConfig.class); 85 + cfgService.getSubjects(DeviceId.class, SegmentRoutingDeviceConfig.class);
82 deviceSubjects.forEach(subject -> { 86 deviceSubjects.forEach(subject -> {
83 - SegmentRoutingConfig config = 87 + SegmentRoutingDeviceConfig config =
84 - cfgService.getConfig(subject, SegmentRoutingConfig.class); 88 + cfgService.getConfig(subject, SegmentRoutingDeviceConfig.class);
85 SegmentRouterInfo info = new SegmentRouterInfo(); 89 SegmentRouterInfo info = new SegmentRouterInfo();
86 info.deviceId = subject; 90 info.deviceId = subject;
87 info.nodeSid = config.nodeSid(); 91 info.nodeSid = config.nodeSid();
...@@ -119,7 +123,11 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -119,7 +123,11 @@ public class DeviceConfiguration implements DeviceProperties {
119 // Extract subnet information 123 // Extract subnet information
120 Set<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddresses(); 124 Set<InterfaceIpAddress> interfaceAddresses = networkInterface.ipAddresses();
121 interfaceAddresses.forEach(interfaceAddress -> { 125 interfaceAddresses.forEach(interfaceAddress -> {
122 - info.gatewayIps.put(port, interfaceAddress.ipAddress().getIp4Address()); 126 + // Do not add /0 and /32 to gateway IP list
127 + int prefixLength = interfaceAddress.subnetAddress().prefixLength();
128 + if (prefixLength != 0 && prefixLength != IpPrefix.MAX_INET_MASK_LENGTH) {
129 + info.gatewayIps.put(port, interfaceAddress.ipAddress().getIp4Address());
130 + }
123 info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix()); 131 info.subnets.put(port, interfaceAddress.subnetAddress().getIp4Prefix());
124 }); 132 });
125 133
...@@ -247,9 +255,13 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -247,9 +255,13 @@ public class DeviceConfiguration implements DeviceProperties {
247 Map<Ip4Prefix, List<PortNumber>> subnetPortMap = new HashMap<>(); 255 Map<Ip4Prefix, List<PortNumber>> subnetPortMap = new HashMap<>();
248 256
249 // Construct subnet-port mapping from port-subnet mapping 257 // Construct subnet-port mapping from port-subnet mapping
250 - Map<PortNumber, Ip4Prefix> portSubnetMap = 258 + SetMultimap<PortNumber, Ip4Prefix> portSubnetMap =
251 this.deviceConfigMap.get(deviceId).subnets; 259 this.deviceConfigMap.get(deviceId).subnets;
252 - portSubnetMap.forEach((port, subnet) -> { 260 +
261 + portSubnetMap.entries().forEach(entry -> {
262 + PortNumber port = entry.getKey();
263 + Ip4Prefix subnet = entry.getValue();
264 +
253 if (subnetPortMap.containsKey(subnet)) { 265 if (subnetPortMap.containsKey(subnet)) {
254 subnetPortMap.get(subnet).add(port); 266 subnetPortMap.get(subnet).add(port);
255 } else { 267 } else {
...@@ -258,7 +270,6 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -258,7 +270,6 @@ public class DeviceConfiguration implements DeviceProperties {
258 subnetPortMap.put(subnet, ports); 270 subnetPortMap.put(subnet, ports);
259 } 271 }
260 }); 272 });
261 -
262 return subnetPortMap; 273 return subnetPortMap;
263 } 274 }
264 275
...@@ -322,21 +333,6 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -322,21 +333,6 @@ public class DeviceConfiguration implements DeviceProperties {
322 } 333 }
323 334
324 /** 335 /**
325 - * Returns the configured IP addresses per port
326 - * for a segment router.
327 - *
328 - * @param deviceId device identifier
329 - * @return map of port to gateway IP addresses or null if not found
330 - */
331 - public Map<PortNumber, Ip4Address> getPortIPMap(DeviceId deviceId) {
332 - SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
333 - if (srinfo != null) {
334 - return srinfo.gatewayIps;
335 - }
336 - return null;
337 - }
338 -
339 - /**
340 * Returns the configured subnet prefixes for a segment router. 336 * Returns the configured subnet prefixes for a segment router.
341 * 337 *
342 * @param deviceId device identifier 338 * @param deviceId device identifier
...@@ -353,8 +349,8 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -353,8 +349,8 @@ public class DeviceConfiguration implements DeviceProperties {
353 } 349 }
354 350
355 /** 351 /**
356 - * Returns the configured subnet on the given port, or null if no 352 + * Returns the configured non-/32 and non-/0 subnet on the given port,
357 - * subnet has been configured on the port. 353 + * or null if no subnet has been configured on the port.
358 * 354 *
359 * @param deviceId device identifier 355 * @param deviceId device identifier
360 * @param pnum port identifier 356 * @param pnum port identifier
...@@ -363,7 +359,12 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -363,7 +359,12 @@ public class DeviceConfiguration implements DeviceProperties {
363 public Ip4Prefix getPortSubnet(DeviceId deviceId, PortNumber pnum) { 359 public Ip4Prefix getPortSubnet(DeviceId deviceId, PortNumber pnum) {
364 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId); 360 SegmentRouterInfo srinfo = deviceConfigMap.get(deviceId);
365 if (srinfo != null) { 361 if (srinfo != null) {
366 - return srinfo.subnets.get(pnum); 362 + Optional<Ip4Prefix> result = srinfo.subnets.get(pnum).stream()
363 + .filter(subnet ->
364 + subnet.getIp4Prefix().prefixLength() != IpPrefix.MAX_INET_MASK_LENGTH &&
365 + subnet.getIp4Prefix().prefixLength() != 0)
366 + .findFirst();
367 + return (result.isPresent()) ? result.get() : null;
367 } 368 }
368 return null; 369 return null;
369 } 370 }
...@@ -378,7 +379,7 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -378,7 +379,7 @@ public class DeviceConfiguration implements DeviceProperties {
378 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) { 379 public Ip4Address getRouterIpAddressForASubnetHost(Ip4Address destIpAddress) {
379 for (Map.Entry<DeviceId, SegmentRouterInfo> entry: 380 for (Map.Entry<DeviceId, SegmentRouterInfo> entry:
380 deviceConfigMap.entrySet()) { 381 deviceConfigMap.entrySet()) {
381 - for (Ip4Prefix prefix:entry.getValue().subnets.values()) { 382 + for (Ip4Prefix prefix : entry.getValue().subnets.values()) {
382 if (prefix.contains(destIpAddress)) { 383 if (prefix.contains(destIpAddress)) {
383 return entry.getValue().ip; 384 return entry.getValue().ip;
384 } 385 }
...@@ -428,7 +429,8 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -428,7 +429,8 @@ public class DeviceConfiguration implements DeviceProperties {
428 } 429 }
429 430
430 for (Ip4Prefix subnet: subnets) { 431 for (Ip4Prefix subnet: subnets) {
431 - if (subnet.contains(hostIp)) { 432 + // Exclude /0 since it is a special case used for default route
433 + if (subnet.prefixLength() != 0 && subnet.contains(hostIp)) {
432 return true; 434 return true;
433 } 435 }
434 } 436 }
......
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.segmentrouting.config;
18 +
19 +import com.fasterxml.jackson.databind.JsonNode;
20 +import com.fasterxml.jackson.databind.node.ArrayNode;
21 +import com.google.common.collect.ImmutableSet;
22 +import org.onlab.packet.MacAddress;
23 +import org.onosproject.core.ApplicationId;
24 +import org.onosproject.net.config.Config;
25 +import java.util.Set;
26 +
27 +import static com.google.common.base.MoreObjects.toStringHelper;
28 +
29 +/**
30 + * App configuration object for Segment Routing.
31 + */
32 +public class SegmentRoutingAppConfig extends Config<ApplicationId> {
33 + private static final String VROUTER_MACS = "vRouterMacs";
34 +
35 + @Override
36 + public boolean isValid() {
37 + return hasOnlyFields(VROUTER_MACS) && vRouterMacs() != null;
38 + }
39 +
40 + /**
41 + * Gets vRouters from the config.
42 + *
43 + * @return a set of vRouter MAC addresses
44 + */
45 + public Set<MacAddress> vRouterMacs() {
46 + if (!object.has(VROUTER_MACS)) {
47 + return null;
48 + }
49 +
50 + ImmutableSet.Builder<MacAddress> builder = ImmutableSet.builder();
51 + ArrayNode arrayNode = (ArrayNode) object.path(VROUTER_MACS);
52 + for (JsonNode jsonNode : arrayNode) {
53 + MacAddress mac;
54 +
55 + String macStr = jsonNode.asText(null);
56 + if (macStr == null) {
57 + return null;
58 + }
59 + try {
60 + mac = MacAddress.valueOf(macStr);
61 + } catch (IllegalArgumentException e) {
62 + return null;
63 + }
64 +
65 + builder.add(mac);
66 + }
67 + return builder.build();
68 + }
69 +
70 + /**
71 + * Sets vRouters to the config.
72 + *
73 + * @param vRouterMacs a set of vRouter MAC addresses
74 + * @return this {@link SegmentRoutingAppConfig}
75 + */
76 + public SegmentRoutingAppConfig setVRouterMacs(Set<MacAddress> vRouterMacs) {
77 + if (vRouterMacs == null) {
78 + object.remove(VROUTER_MACS);
79 + } else {
80 + ArrayNode arrayNode = mapper.createArrayNode();
81 +
82 + vRouterMacs.forEach(mac -> {
83 + arrayNode.add(mac.toString());
84 + });
85 +
86 + object.set(VROUTER_MACS, arrayNode);
87 + }
88 + return this;
89 + }
90 +
91 + @Override
92 + public String toString() {
93 + return toStringHelper(this)
94 + .add("vRouterMacs", vRouterMacs())
95 + .toString();
96 + }
97 +}
...@@ -34,7 +34,7 @@ import java.util.Set; ...@@ -34,7 +34,7 @@ import java.util.Set;
34 /** 34 /**
35 * Configuration object for Segment Routing Application. 35 * Configuration object for Segment Routing Application.
36 */ 36 */
37 -public class SegmentRoutingConfig extends Config<DeviceId> { 37 +public class SegmentRoutingDeviceConfig extends Config<DeviceId> {
38 private static final String NAME = "name"; 38 private static final String NAME = "name";
39 private static final String IP = "routerIp"; 39 private static final String IP = "routerIp";
40 private static final String MAC = "routerMac"; 40 private static final String MAC = "routerMac";
...@@ -71,8 +71,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> { ...@@ -71,8 +71,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
71 * @param name name of the router. 71 * @param name name of the router.
72 * @return the config of the router. 72 * @return the config of the router.
73 */ 73 */
74 - public SegmentRoutingConfig setName(String name) { 74 + public SegmentRoutingDeviceConfig setName(String name) {
75 - return (SegmentRoutingConfig) setOrClear(NAME, name); 75 + return (SegmentRoutingDeviceConfig) setOrClear(NAME, name);
76 } 76 }
77 77
78 /** 78 /**
...@@ -91,8 +91,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> { ...@@ -91,8 +91,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
91 * @param ip IP address of the router. 91 * @param ip IP address of the router.
92 * @return the config of the router. 92 * @return the config of the router.
93 */ 93 */
94 - public SegmentRoutingConfig setRouterIp(String ip) { 94 + public SegmentRoutingDeviceConfig setRouterIp(String ip) {
95 - return (SegmentRoutingConfig) setOrClear(IP, ip); 95 + return (SegmentRoutingDeviceConfig) setOrClear(IP, ip);
96 } 96 }
97 97
98 /** 98 /**
...@@ -111,8 +111,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> { ...@@ -111,8 +111,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
111 * @param mac MAC address of the router. 111 * @param mac MAC address of the router.
112 * @return the config of the router. 112 * @return the config of the router.
113 */ 113 */
114 - public SegmentRoutingConfig setRouterMac(String mac) { 114 + public SegmentRoutingDeviceConfig setRouterMac(String mac) {
115 - return (SegmentRoutingConfig) setOrClear(MAC, mac); 115 + return (SegmentRoutingDeviceConfig) setOrClear(MAC, mac);
116 } 116 }
117 117
118 /** 118 /**
...@@ -130,8 +130,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> { ...@@ -130,8 +130,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
130 * @param sid node SID of the router. 130 * @param sid node SID of the router.
131 * @return the config of the router. 131 * @return the config of the router.
132 */ 132 */
133 - public SegmentRoutingConfig setNodeSid(int sid) { 133 + public SegmentRoutingDeviceConfig setNodeSid(int sid) {
134 - return (SegmentRoutingConfig) setOrClear(SID, sid); 134 + return (SegmentRoutingDeviceConfig) setOrClear(SID, sid);
135 } 135 }
136 136
137 /** 137 /**
...@@ -154,8 +154,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> { ...@@ -154,8 +154,8 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
154 * @param isEdgeRouter true if the router is an edge router. 154 * @param isEdgeRouter true if the router is an edge router.
155 * @return the config of the router. 155 * @return the config of the router.
156 */ 156 */
157 - public SegmentRoutingConfig setIsEdgeRouter(boolean isEdgeRouter) { 157 + public SegmentRoutingDeviceConfig setIsEdgeRouter(boolean isEdgeRouter) {
158 - return (SegmentRoutingConfig) setOrClear(EDGE, isEdgeRouter); 158 + return (SegmentRoutingDeviceConfig) setOrClear(EDGE, isEdgeRouter);
159 } 159 }
160 160
161 /** 161 /**
...@@ -197,7 +197,7 @@ public class SegmentRoutingConfig extends Config<DeviceId> { ...@@ -197,7 +197,7 @@ public class SegmentRoutingConfig extends Config<DeviceId> {
197 * @param adjacencySids adjacency SIDs of the router. 197 * @param adjacencySids adjacency SIDs of the router.
198 * @return the config of the router. 198 * @return the config of the router.
199 */ 199 */
200 - public SegmentRoutingConfig setAdjacencySids(Map<Integer, Set<Integer>> adjacencySids) { 200 + public SegmentRoutingDeviceConfig setAdjacencySids(Map<Integer, Set<Integer>> adjacencySids) {
201 if (adjacencySids == null) { 201 if (adjacencySids == null) {
202 object.remove(ADJSIDS); 202 object.remove(ADJSIDS);
203 } else { 203 } else {
......
1 +/*
2 + * Copyright 2016 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +package org.onosproject.segmentrouting.config;
18 +
19 +import com.fasterxml.jackson.databind.JsonNode;
20 +import com.fasterxml.jackson.databind.ObjectMapper;
21 +import com.google.common.collect.ImmutableSet;
22 +import org.junit.Before;
23 +import org.junit.Test;
24 +import org.onlab.packet.MacAddress;
25 +import org.onosproject.core.ApplicationId;
26 +import org.onosproject.TestApplicationId;
27 +import org.onosproject.net.config.Config;
28 +import org.onosproject.net.config.ConfigApplyDelegate;
29 +import org.onosproject.segmentrouting.SegmentRoutingService;
30 +import java.util.Set;
31 +
32 +import static org.hamcrest.Matchers.is;
33 +import static org.junit.Assert.assertThat;
34 +import static org.junit.Assert.assertTrue;
35 +
36 +/**
37 + * Tests for class {@link SegmentRoutingAppConfig}.
38 + */
39 +public class SegmentRoutingAppConfigTest {
40 + private static final ApplicationId APP_ID =
41 + new TestApplicationId(SegmentRoutingService.SR_APP_ID);
42 +
43 + private SegmentRoutingAppConfig config;
44 + private MacAddress routerMac1;
45 + private MacAddress routerMac2;
46 + private MacAddress routerMac3;
47 +
48 + /**
49 + * Initialize test related variables.
50 + *
51 + * @throws Exception
52 + */
53 + @Before
54 + public void setUp() throws Exception {
55 + String jsonString = "{" +
56 + "\"vRouterMacs\" : [" +
57 + " \"00:00:00:00:00:01\"," +
58 + " \"00:00:00:00:00:02\"" +
59 + "]}";
60 +
61 + routerMac1 = MacAddress.valueOf("00:00:00:00:00:01");
62 + routerMac2 = MacAddress.valueOf("00:00:00:00:00:02");
63 + routerMac3 = MacAddress.valueOf("00:00:00:00:00:03");
64 +
65 + ApplicationId subject = APP_ID;
66 + String key = SegmentRoutingService.SR_APP_ID;
67 + ObjectMapper mapper = new ObjectMapper();
68 + JsonNode jsonNode = mapper.readTree(jsonString);
69 + ConfigApplyDelegate delegate = new MockDelegate();
70 +
71 + config = new SegmentRoutingAppConfig();
72 + config.init(subject, key, jsonNode, mapper, delegate);
73 + }
74 +
75 + /**
76 + * Tests vRouters getter.
77 + *
78 + * @throws Exception
79 + */
80 + @Test
81 + public void testVRouters() throws Exception {
82 + assertTrue(config.isValid());
83 +
84 + Set<MacAddress> vRouters = config.vRouterMacs();
85 + assertThat(vRouters.size(), is(2));
86 + assertTrue(vRouters.contains(routerMac1));
87 + assertTrue(vRouters.contains(routerMac2));
88 + }
89 +
90 + /**
91 + * Tests vRouters setter.
92 + *
93 + * @throws Exception
94 + */
95 + @Test
96 + public void testSetVRouters() throws Exception {
97 + ImmutableSet.Builder<MacAddress> builder = ImmutableSet.builder();
98 + builder.add(routerMac3);
99 + config.setVRouterMacs(builder.build());
100 +
101 + Set<MacAddress> macs = config.vRouterMacs();
102 + assertThat(macs.size(), is(1));
103 + assertTrue(macs.contains(routerMac3));
104 + }
105 +
106 + private class MockDelegate implements ConfigApplyDelegate {
107 + @Override
108 + public void onApply(Config config) {
109 + }
110 + }
111 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -36,10 +36,10 @@ import static org.hamcrest.Matchers.is; ...@@ -36,10 +36,10 @@ import static org.hamcrest.Matchers.is;
36 import static org.junit.Assert.assertTrue; 36 import static org.junit.Assert.assertTrue;
37 37
38 /** 38 /**
39 - * Tests for class {@link SegmentRoutingConfig}. 39 + * Tests for class {@link SegmentRoutingDeviceConfig}.
40 */ 40 */
41 -public class SegmentRoutingConfigTest { 41 +public class SegmentRoutingDeviceConfigTest {
42 - private SegmentRoutingConfig config; 42 + private SegmentRoutingDeviceConfig config;
43 private Map<Integer, Set<Integer>> adjacencySids1; 43 private Map<Integer, Set<Integer>> adjacencySids1;
44 private Map<Integer, Set<Integer>> adjacencySids2; 44 private Map<Integer, Set<Integer>> adjacencySids2;
45 45
...@@ -72,12 +72,12 @@ public class SegmentRoutingConfigTest { ...@@ -72,12 +72,12 @@ public class SegmentRoutingConfigTest {
72 adjacencySids2.put(300, ports3); 72 adjacencySids2.put(300, ports3);
73 73
74 DeviceId subject = DeviceId.deviceId("of:0000000000000001"); 74 DeviceId subject = DeviceId.deviceId("of:0000000000000001");
75 - String key = "org.onosproject.segmentrouting"; 75 + String key = "segmentrouting";
76 ObjectMapper mapper = new ObjectMapper(); 76 ObjectMapper mapper = new ObjectMapper();
77 JsonNode jsonNode = mapper.readTree(jsonString); 77 JsonNode jsonNode = mapper.readTree(jsonString);
78 ConfigApplyDelegate delegate = new MockDelegate(); 78 ConfigApplyDelegate delegate = new MockDelegate();
79 79
80 - config = new SegmentRoutingConfig(); 80 + config = new SegmentRoutingDeviceConfig();
81 config.init(subject, key, jsonNode, mapper, delegate); 81 config.init(subject, key, jsonNode, mapper, delegate);
82 } 82 }
83 83
......
...@@ -44,8 +44,9 @@ public final class PortNumber { ...@@ -44,8 +44,9 @@ public final class PortNumber {
44 static final long NORMAL_NUMBER = -6L; 44 static final long NORMAL_NUMBER = -6L;
45 static final long FLOOD_NUMBER = -5L; 45 static final long FLOOD_NUMBER = -5L;
46 static final long ALL_NUMBER = -4L; 46 static final long ALL_NUMBER = -4L;
47 - static final long LOCAL_NUMBER = -2L;
48 static final long CONTROLLER_NUMBER = -3L; 47 static final long CONTROLLER_NUMBER = -3L;
48 + static final long LOCAL_NUMBER = -2L;
49 + static final long ANY_NUMBER = -1L;
49 50
50 /** 51 /**
51 * Logical PortNumbers. 52 * Logical PortNumbers.
...@@ -57,7 +58,8 @@ public final class PortNumber { ...@@ -57,7 +58,8 @@ public final class PortNumber {
57 FLOOD(FLOOD_NUMBER), 58 FLOOD(FLOOD_NUMBER),
58 ALL(ALL_NUMBER), 59 ALL(ALL_NUMBER),
59 LOCAL(LOCAL_NUMBER), 60 LOCAL(LOCAL_NUMBER),
60 - CONTROLLER(CONTROLLER_NUMBER); 61 + CONTROLLER(CONTROLLER_NUMBER),
62 + ANY(ANY_NUMBER);
61 63
62 private final long number; 64 private final long number;
63 private final PortNumber instance; 65 private final PortNumber instance;
...@@ -88,6 +90,7 @@ public final class PortNumber { ...@@ -88,6 +90,7 @@ public final class PortNumber {
88 public static final PortNumber ALL = new PortNumber(ALL_NUMBER); 90 public static final PortNumber ALL = new PortNumber(ALL_NUMBER);
89 public static final PortNumber LOCAL = new PortNumber(LOCAL_NUMBER); 91 public static final PortNumber LOCAL = new PortNumber(LOCAL_NUMBER);
90 public static final PortNumber CONTROLLER = new PortNumber(CONTROLLER_NUMBER); 92 public static final PortNumber CONTROLLER = new PortNumber(CONTROLLER_NUMBER);
93 + public static final PortNumber ANY = new PortNumber(ANY_NUMBER);
91 94
92 // lazily populated Logical port number to PortNumber 95 // lazily populated Logical port number to PortNumber
93 static final Supplier<Map<Long, Logical>> LOGICAL = Suppliers.memoize(() -> { 96 static final Supplier<Map<Long, Logical>> LOGICAL = Suppliers.memoize(() -> {
......
...@@ -25,6 +25,7 @@ import java.util.List; ...@@ -25,6 +25,7 @@ import java.util.List;
25 import java.util.Set; 25 import java.util.Set;
26 import java.util.concurrent.ConcurrentHashMap; 26 import java.util.concurrent.ConcurrentHashMap;
27 27
28 +import com.google.common.collect.ImmutableList;
28 import org.onlab.packet.Ethernet; 29 import org.onlab.packet.Ethernet;
29 import org.onlab.packet.MacAddress; 30 import org.onlab.packet.MacAddress;
30 import org.onlab.packet.IpPrefix; 31 import org.onlab.packet.IpPrefix;
...@@ -288,6 +289,11 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -288,6 +289,11 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
288 VlanIdCriterion vidCriterion, 289 VlanIdCriterion vidCriterion,
289 VlanId assignedVlan, 290 VlanId assignedVlan,
290 ApplicationId applicationId) { 291 ApplicationId applicationId) {
292 + // Consider PortNumber.ANY as wildcard. Match ETH_DST only
293 + if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
294 + return processEthDstOnlyFilter(ethCriterion, applicationId);
295 + }
296 +
291 //handling untagged packets via assigned VLAN 297 //handling untagged packets via assigned VLAN
292 if (vidCriterion.vlanId() == VlanId.NONE) { 298 if (vidCriterion.vlanId() == VlanId.NONE) {
293 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); 299 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
...@@ -354,6 +360,32 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -354,6 +360,32 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
354 return rules; 360 return rules;
355 } 361 }
356 362
363 + @Override
364 + protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
365 + ApplicationId applicationId) {
366 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
367 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
368 + selector.matchEthType(Ethernet.TYPE_IPV4);
369 + selector.matchEthDst(ethCriterion.mac());
370 + /*
371 + * Note: CpqD switches do not handle MPLS-related operation properly
372 + * for a packet with VLAN tag. We pop VLAN here as a workaround.
373 + * Side effect: HostService learns redundant hosts with same MAC but
374 + * different VLAN. No known side effect on the network reachability.
375 + */
376 + treatment.popVlan();
377 + treatment.transition(UNICAST_ROUTING_TABLE);
378 + FlowRule rule = DefaultFlowRule.builder()
379 + .forDevice(deviceId)
380 + .withSelector(selector.build())
381 + .withTreatment(treatment.build())
382 + .withPriority(DEFAULT_PRIORITY)
383 + .fromApp(applicationId)
384 + .makePermanent()
385 + .forTable(TMAC_TABLE).build();
386 + return ImmutableList.<FlowRule>builder().add(rule).build();
387 + }
388 +
357 /* 389 /*
358 * Cpqd emulation allows MPLS ecmp. 390 * Cpqd emulation allows MPLS ecmp.
359 * 391 *
...@@ -600,6 +632,7 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline { ...@@ -600,6 +632,7 @@ public class CpqdOFDPA2Pipeline extends OFDPA2Pipeline {
600 log.warn("Cannot process instruction in versatile fwd {}", ins); 632 log.warn("Cannot process instruction in versatile fwd {}", ins);
601 } 633 }
602 } 634 }
635 + ttBuilder.wipeDeferred();
603 } 636 }
604 if (fwd.nextId() != null) { 637 if (fwd.nextId() != null) {
605 // overide case 638 // overide case
......
...@@ -78,6 +78,11 @@ public class CpqdOFDPA2VlanPipeline extends CpqdOFDPA2Pipeline { ...@@ -78,6 +78,11 @@ public class CpqdOFDPA2VlanPipeline extends CpqdOFDPA2Pipeline {
78 VlanIdCriterion vidCriterion, 78 VlanIdCriterion vidCriterion,
79 VlanId assignedVlan, 79 VlanId assignedVlan,
80 ApplicationId applicationId) { 80 ApplicationId applicationId) {
81 + // Consider PortNumber.ANY as wildcard. Match ETH_DST only
82 + if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
83 + return processEthDstOnlyFilter(ethCriterion, applicationId);
84 + }
85 +
81 //handling untagged packets via assigned VLAN 86 //handling untagged packets via assigned VLAN
82 if (vidCriterion.vlanId() == VlanId.NONE) { 87 if (vidCriterion.vlanId() == VlanId.NONE) {
83 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); 88 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
......
...@@ -6,6 +6,7 @@ import com.google.common.cache.CacheBuilder; ...@@ -6,6 +6,7 @@ import com.google.common.cache.CacheBuilder;
6 import com.google.common.cache.RemovalCause; 6 import com.google.common.cache.RemovalCause;
7 import com.google.common.cache.RemovalNotification; 7 import com.google.common.cache.RemovalNotification;
8 import org.onlab.osgi.ServiceDirectory; 8 import org.onlab.osgi.ServiceDirectory;
9 +import org.onlab.packet.MacAddress;
9 import org.onlab.packet.MplsLabel; 10 import org.onlab.packet.MplsLabel;
10 import org.onlab.packet.VlanId; 11 import org.onlab.packet.VlanId;
11 import org.onosproject.core.ApplicationId; 12 import org.onosproject.core.ApplicationId;
...@@ -95,7 +96,7 @@ public class OFDPA2GroupHandler { ...@@ -95,7 +96,7 @@ public class OFDPA2GroupHandler {
95 Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", "ofdpa2-%d")); 96 Executors.newScheduledThreadPool(2, groupedThreads("onos/pipeliner", "ofdpa2-%d"));
96 97
97 // index number for group creation 98 // index number for group creation
98 - private AtomicInteger l3vpnindex = new AtomicInteger(0); 99 + private AtomicInteger l3VpnIndex = new AtomicInteger(0);
99 100
100 // local stores for port-vlan mapping 101 // local stores for port-vlan mapping
101 protected Map<PortNumber, VlanId> port2Vlan = new ConcurrentHashMap<>(); 102 protected Map<PortNumber, VlanId> port2Vlan = new ConcurrentHashMap<>();
...@@ -332,12 +333,14 @@ public class OFDPA2GroupHandler { ...@@ -332,12 +333,14 @@ public class OFDPA2GroupHandler {
332 VlanId vlanid = null; 333 VlanId vlanid = null;
333 long portNum = 0; 334 long portNum = 0;
334 boolean setVlan = false, popVlan = false; 335 boolean setVlan = false, popVlan = false;
336 + MacAddress dstMac = MacAddress.ZERO;
335 for (Instruction ins : treatment.allInstructions()) { 337 for (Instruction ins : treatment.allInstructions()) {
336 if (ins.type() == Instruction.Type.L2MODIFICATION) { 338 if (ins.type() == Instruction.Type.L2MODIFICATION) {
337 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins; 339 L2ModificationInstruction l2ins = (L2ModificationInstruction) ins;
338 switch (l2ins.subtype()) { 340 switch (l2ins.subtype()) {
339 case ETH_DST: 341 case ETH_DST:
340 - outerTtb.setEthDst(((L2ModificationInstruction.ModEtherInstruction) l2ins).mac()); 342 + dstMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
343 + outerTtb.setEthDst(dstMac);
341 break; 344 break;
342 case ETH_SRC: 345 case ETH_SRC:
343 outerTtb.setEthSrc(((L2ModificationInstruction.ModEtherInstruction) l2ins).mac()); 346 outerTtb.setEthSrc(((L2ModificationInstruction.ModEtherInstruction) l2ins).mac());
...@@ -430,8 +433,11 @@ public class OFDPA2GroupHandler { ...@@ -430,8 +433,11 @@ public class OFDPA2GroupHandler {
430 mplsgroupkey, nextId); 433 mplsgroupkey, nextId);
431 } else { 434 } else {
432 // outer group is L3Unicast 435 // outer group is L3Unicast
433 - int l3groupId = L3_UNICAST_TYPE | (int) portNum; 436 + int l3groupId = L3_UNICAST_TYPE |
434 - int l3gk = L3_UNICAST_TYPE | (TYPE_MASK & (deviceId.hashCode() << 8 | (int) portNum)); 437 + (TYPE_MASK & (int) (dstMac.toLong() & 0xffff) << 6 | (int) portNum);
438 + int l3gk = L3_UNICAST_TYPE |
439 + (TYPE_MASK & (deviceId.hashCode() << 22 |
440 + (int) (dstMac.toLong() & 0xffff) << 6 | (int) portNum));
435 final GroupKey l3groupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3gk)); 441 final GroupKey l3groupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3gk));
436 outerTtb.group(new DefaultGroupId(l2groupId)); 442 outerTtb.group(new DefaultGroupId(l2groupId));
437 // create the l3unicast group description to wait for the 443 // create the l3unicast group description to wait for the
...@@ -734,8 +740,8 @@ public class OFDPA2GroupHandler { ...@@ -734,8 +740,8 @@ public class OFDPA2GroupHandler {
734 onelabelGroupInfo.outerGrpDesc.givenGroupId())); 740 onelabelGroupInfo.outerGrpDesc.givenGroupId()));
735 GroupBucket l3vpnGrpBkt = 741 GroupBucket l3vpnGrpBkt =
736 DefaultGroupBucket.createIndirectGroupBucket(l3vpnTtb.build()); 742 DefaultGroupBucket.createIndirectGroupBucket(l3vpnTtb.build());
737 - int l3vpngroupId = MPLS_L3VPN_SUBTYPE | l3vpnindex.incrementAndGet(); 743 + int l3vpngroupId = MPLS_L3VPN_SUBTYPE | l3VpnIndex.incrementAndGet();
738 - int l3vpngk = MPLS_L3VPN_SUBTYPE | nextObj.id() << 12 | l3vpnindex.get(); 744 + int l3vpngk = MPLS_L3VPN_SUBTYPE | nextObj.id() << 12 | l3VpnIndex.get();
739 GroupKey l3vpngroupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3vpngk)); 745 GroupKey l3vpngroupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3vpngk));
740 GroupDescription l3vpnGroupDesc = 746 GroupDescription l3vpnGroupDesc =
741 new DefaultGroupDescription( 747 new DefaultGroupDescription(
......
...@@ -27,6 +27,7 @@ import java.util.Objects; ...@@ -27,6 +27,7 @@ import java.util.Objects;
27 import java.util.Set; 27 import java.util.Set;
28 import java.util.concurrent.ConcurrentHashMap; 28 import java.util.concurrent.ConcurrentHashMap;
29 29
30 +import com.google.common.collect.ImmutableList;
30 import org.onlab.osgi.ServiceDirectory; 31 import org.onlab.osgi.ServiceDirectory;
31 import org.onlab.packet.Ethernet; 32 import org.onlab.packet.Ethernet;
32 import org.onlab.packet.IpPrefix; 33 import org.onlab.packet.IpPrefix;
...@@ -553,6 +554,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -553,6 +554,11 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
553 VlanIdCriterion vidCriterion, 554 VlanIdCriterion vidCriterion,
554 VlanId assignedVlan, 555 VlanId assignedVlan,
555 ApplicationId applicationId) { 556 ApplicationId applicationId) {
557 + // Consider PortNumber.ANY as wildcard. Match ETH_DST only
558 + if (portCriterion != null && portCriterion.port() == PortNumber.ANY) {
559 + return processEthDstOnlyFilter(ethCriterion, applicationId);
560 + }
561 +
556 //handling untagged packets via assigned VLAN 562 //handling untagged packets via assigned VLAN
557 if (vidCriterion.vlanId() == VlanId.NONE) { 563 if (vidCriterion.vlanId() == VlanId.NONE) {
558 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); 564 vidCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
...@@ -611,6 +617,24 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline ...@@ -611,6 +617,24 @@ public class OFDPA2Pipeline extends AbstractHandlerBehaviour implements Pipeline
611 return rules; 617 return rules;
612 } 618 }
613 619
620 + protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
621 + ApplicationId applicationId) {
622 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
623 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
624 + selector.matchEthType(Ethernet.TYPE_IPV4);
625 + selector.matchEthDst(ethCriterion.mac());
626 + treatment.transition(UNICAST_ROUTING_TABLE);
627 + FlowRule rule = DefaultFlowRule.builder()
628 + .forDevice(deviceId)
629 + .withSelector(selector.build())
630 + .withTreatment(treatment.build())
631 + .withPriority(DEFAULT_PRIORITY)
632 + .fromApp(applicationId)
633 + .makePermanent()
634 + .forTable(TMAC_TABLE).build();
635 + return ImmutableList.<FlowRule>builder().add(rule).build();
636 + }
637 +
614 private Collection<FlowRule> processForward(ForwardingObjective fwd) { 638 private Collection<FlowRule> processForward(ForwardingObjective fwd) {
615 switch (fwd.flag()) { 639 switch (fwd.flag()) {
616 case SPECIFIC: 640 case SPECIFIC:
......
...@@ -23,6 +23,7 @@ import com.google.common.cache.CacheBuilder; ...@@ -23,6 +23,7 @@ import com.google.common.cache.CacheBuilder;
23 import com.google.common.cache.RemovalCause; 23 import com.google.common.cache.RemovalCause;
24 import com.google.common.cache.RemovalNotification; 24 import com.google.common.cache.RemovalNotification;
25 25
26 +import com.google.common.collect.ImmutableList;
26 import org.onlab.osgi.ServiceDirectory; 27 import org.onlab.osgi.ServiceDirectory;
27 import org.onlab.packet.Ethernet; 28 import org.onlab.packet.Ethernet;
28 import org.onlab.packet.MacAddress; 29 import org.onlab.packet.MacAddress;
...@@ -504,6 +505,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ...@@ -504,6 +505,7 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
504 fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) { 505 fwd.treatment().allInstructions().get(0).type() == Instruction.Type.OUTPUT) {
505 OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0); 506 OutputInstruction o = (OutputInstruction) fwd.treatment().allInstructions().get(0);
506 if (o.port() == PortNumber.CONTROLLER) { 507 if (o.port() == PortNumber.CONTROLLER) {
508 + treatmentBuilder.popVlan();
507 treatmentBuilder.punt(); 509 treatmentBuilder.punt();
508 } else { 510 } else {
509 treatmentBuilder.add(o); 511 treatmentBuilder.add(o);
...@@ -780,6 +782,10 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ...@@ -780,6 +782,10 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
780 FilteringObjective filt, 782 FilteringObjective filt,
781 VlanId assignedVlan, 783 VlanId assignedVlan,
782 ApplicationId applicationId) { 784 ApplicationId applicationId) {
785 + if (vlanIdCriterion == null) {
786 + return processEthDstOnlyFilter(ethCriterion, applicationId, filt.priority());
787 + }
788 +
783 //handling untagged packets via assigned VLAN 789 //handling untagged packets via assigned VLAN
784 if (vlanIdCriterion.vlanId() == VlanId.NONE) { 790 if (vlanIdCriterion.vlanId() == VlanId.NONE) {
785 vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan); 791 vlanIdCriterion = (VlanIdCriterion) Criteria.matchVlanId(assignedVlan);
...@@ -823,6 +829,24 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour ...@@ -823,6 +829,24 @@ public class SpringOpenTTP extends AbstractHandlerBehaviour
823 return rules; 829 return rules;
824 } 830 }
825 831
832 + protected List<FlowRule> processEthDstOnlyFilter(EthCriterion ethCriterion,
833 + ApplicationId applicationId, int priority) {
834 + TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
835 + TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
836 + selector.matchEthType(Ethernet.TYPE_IPV4);
837 + selector.matchEthDst(ethCriterion.mac());
838 + treatment.transition(TABLE_IPV4_UNICAST);
839 + FlowRule rule = DefaultFlowRule.builder()
840 + .forDevice(deviceId)
841 + .withSelector(selector.build())
842 + .withTreatment(treatment.build())
843 + .withPriority(priority)
844 + .fromApp(applicationId)
845 + .makePermanent()
846 + .forTable(TABLE_TMAC).build();
847 + return ImmutableList.<FlowRule>builder().add(rule).build();
848 + }
849 +
826 protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion, 850 protected List<FlowRule> processVlanIdFilter(VlanIdCriterion vlanIdCriterion,
827 FilteringObjective filt, 851 FilteringObjective filt,
828 VlanId assignedVlan, 852 VlanId assignedVlan,
......
1 +{
2 + "ports" : {
3 + "of:0000000000000001/3" : {
4 + "interfaces" : [
5 + {
6 + "ips" : [ "10.0.1.254/24" ],
7 + "vlan" : "-1"
8 + }
9 + ]
10 + },
11 + "of:0000000000000001/4" : {
12 + "interfaces" : [
13 + {
14 + "ips" : [ "10.0.1.254/24", "200.0.0.200/32" ],
15 + "vlan" : "-1"
16 + }
17 + ]
18 + },
19 + "of:0000000000000002/3" : {
20 + "interfaces" : [
21 + {
22 + "ips" : [ "10.0.2.254/24" ],
23 + "vlan" : "-1"
24 + }
25 + ]
26 + },
27 + "of:0000000000000002/4" : {
28 + "interfaces" : [
29 + {
30 + "ips" : [ "10.0.2.254/24", "0.0.0.0/0" ],
31 + "vlan" : "-1"
32 + }
33 + ]
34 + }
35 + },
36 + "devices" : {
37 + "of:0000000000000001" : {
38 + "segmentrouting" : {
39 + "name" : "Leaf-R1",
40 + "nodeSid" : 101,
41 + "routerIp" : "10.0.1.254",
42 + "routerMac" : "00:00:00:00:01:80",
43 + "isEdgeRouter" : true,
44 + "adjacencySids" : []
45 + }
46 + },
47 + "of:0000000000000002" : {
48 + "segmentrouting" : {
49 + "name" : "Leaf-R2",
50 + "nodeSid" : 102,
51 + "routerIp" : "10.0.2.254",
52 + "routerMac" : "00:00:00:00:02:80",
53 + "isEdgeRouter" : true,
54 + "adjacencySids" : []
55 + }
56 + },
57 + "of:0000000000000191" : {
58 + "segmentrouting" : {
59 + "name" : "Spine-R1",
60 + "nodeSid" : 103,
61 + "routerIp" : "192.168.0.11",
62 + "routerMac" : "00:00:01:00:11:80",
63 + "isEdgeRouter" : false,
64 + "adjacencySids" : []
65 + }
66 + },
67 + "of:0000000000000192" : {
68 + "segmentrouting" : {
69 + "name" : "Spine-R2",
70 + "nodeSid" : 104,
71 + "routerIp" : "192.168.0.22",
72 + "routerMac" : "00:00:01:00:22:80",
73 + "isEdgeRouter" : false,
74 + "adjacencySids" : []
75 + }
76 + }
77 + },
78 + "hosts" : {
79 + "00:00:00:00:00:01/-1" : {
80 + "basic": {
81 + "ips": ["10.0.1.1"],
82 + "location": "of:0000000000000001/3"
83 + }
84 + },
85 + "00:00:00:00:00:02/-1" : {
86 + "basic": {
87 + "ips": ["10.0.1.2"],
88 + "location": "of:0000000000000001/4"
89 + }
90 + },
91 + "00:00:00:00:00:03/-1" : {
92 + "basic": {
93 + "ips": ["10.0.2.1"],
94 + "location": "of:0000000000000002/3"
95 + }
96 + },
97 + "00:00:00:00:00:04/-1" : {
98 + "basic": {
99 + "ips": ["10.0.2.2"],
100 + "location": "of:0000000000000002/4"
101 + }
102 + },
103 + "00:00:00:aa:00:01/-1" : {
104 + "basic": {
105 + "ips": ["200.0.0.200"],
106 + "location": "of:0000000000000001/4"
107 + }
108 + }
109 + },
110 + "apps" : {
111 + "org.onosproject.segmentrouting" : {
112 + "segmentrouting" : {
113 + "vRouterMacs" : [
114 + "00:00:00:aa:00:02"
115 + ]
116 + }
117 + }
118 + }
119 +}
...@@ -86,25 +86,25 @@ ...@@ -86,25 +86,25 @@
86 } 86 }
87 }, 87 },
88 "hosts" : { 88 "hosts" : {
89 - "00:00:00:00:00:01/4093" : { 89 + "00:00:00:00:00:01/-1" : {
90 "basic": { 90 "basic": {
91 "ips": ["10.0.1.1"], 91 "ips": ["10.0.1.1"],
92 "location": "of:0000000000000001/3" 92 "location": "of:0000000000000001/3"
93 } 93 }
94 }, 94 },
95 - "00:00:00:00:00:02/4093" : { 95 + "00:00:00:00:00:02/-1" : {
96 "basic": { 96 "basic": {
97 "ips": ["10.0.1.2"], 97 "ips": ["10.0.1.2"],
98 "location": "of:0000000000000001/4" 98 "location": "of:0000000000000001/4"
99 } 99 }
100 }, 100 },
101 - "00:00:00:00:00:03/4093" : { 101 + "00:00:00:00:00:03/-1" : {
102 "basic": { 102 "basic": {
103 "ips": ["10.0.2.1"], 103 "ips": ["10.0.2.1"],
104 "location": "of:0000000000000002/3" 104 "location": "of:0000000000000002/3"
105 } 105 }
106 }, 106 },
107 - "00:00:00:00:00:04/4093" : { 107 + "00:00:00:00:00:04/-1" : {
108 "basic": { 108 "basic": {
109 "ips": ["10.0.2.2"], 109 "ips": ["10.0.2.2"],
110 "location": "of:0000000000000002/4" 110 "location": "of:0000000000000002/4"
......
...@@ -148,49 +148,49 @@ ...@@ -148,49 +148,49 @@
148 } 148 }
149 }, 149 },
150 "hosts" : { 150 "hosts" : {
151 - "00:00:00:00:00:01/4093" : { 151 + "00:00:00:00:00:01/-1" : {
152 "basic": { 152 "basic": {
153 "ips": ["10.0.1.1"], 153 "ips": ["10.0.1.1"],
154 "location": "of:0000000000000001/5" 154 "location": "of:0000000000000001/5"
155 } 155 }
156 }, 156 },
157 - "00:00:00:00:00:02/4093" : { 157 + "00:00:00:00:00:02/-1" : {
158 "basic": { 158 "basic": {
159 "ips": ["10.0.1.2"], 159 "ips": ["10.0.1.2"],
160 "location": "of:0000000000000001/6" 160 "location": "of:0000000000000001/6"
161 } 161 }
162 }, 162 },
163 - "00:00:00:00:00:03/4093" : { 163 + "00:00:00:00:00:03/-1" : {
164 "basic": { 164 "basic": {
165 "ips": ["10.0.2.1"], 165 "ips": ["10.0.2.1"],
166 "location": "of:0000000000000002/5" 166 "location": "of:0000000000000002/5"
167 } 167 }
168 }, 168 },
169 - "00:00:00:00:00:04/4093" : { 169 + "00:00:00:00:00:04/-1" : {
170 "basic": { 170 "basic": {
171 "ips": ["10.0.2.2"], 171 "ips": ["10.0.2.2"],
172 "location": "of:0000000000000002/6" 172 "location": "of:0000000000000002/6"
173 } 173 }
174 }, 174 },
175 - "00:00:00:00:00:05/4093" : { 175 + "00:00:00:00:00:05/-1" : {
176 "basic": { 176 "basic": {
177 "ips": ["10.0.3.1"], 177 "ips": ["10.0.3.1"],
178 "location": "of:0000000000000003/5" 178 "location": "of:0000000000000003/5"
179 } 179 }
180 }, 180 },
181 - "00:00:00:00:00:06/4093" : { 181 + "00:00:00:00:00:06/-1" : {
182 "basic": { 182 "basic": {
183 "ips": ["10.0.3.2"], 183 "ips": ["10.0.3.2"],
184 "location": "of:0000000000000003/6" 184 "location": "of:0000000000000003/6"
185 } 185 }
186 }, 186 },
187 - "00:00:00:00:00:07/4093" : { 187 + "00:00:00:00:00:07/-1" : {
188 "basic": { 188 "basic": {
189 "ips": ["10.0.4.1"], 189 "ips": ["10.0.4.1"],
190 "location": "of:0000000000000004/5" 190 "location": "of:0000000000000004/5"
191 } 191 }
192 }, 192 },
193 - "00:00:00:00:00:08/4093" : { 193 + "00:00:00:00:00:08/-1" : {
194 "basic": { 194 "basic": {
195 "ips": ["10.0.4.2"], 195 "ips": ["10.0.4.2"],
196 "location": "of:0000000000000004/6" 196 "location": "of:0000000000000004/6"
......