Hyunsun Moon
Committed by Gerrit Code Review

Refactored OpenstackRouting to support multiple gateway nodes

Change-Id: I6870ca9a4fd6f6b1cf2d2be72f52ef87827e1d2c
Showing 23 changed files with 2086 additions and 2370 deletions
...@@ -20,7 +20,7 @@ import java.util.Objects; ...@@ -20,7 +20,7 @@ import java.util.Objects;
20 import static com.google.common.base.Preconditions.checkNotNull; 20 import static com.google.common.base.Preconditions.checkNotNull;
21 21
22 /** 22 /**
23 - * An Openstack Neutron Router Interface Model. 23 + * An OpenStack Neutron router interface model.
24 */ 24 */
25 public final class OpenstackRouterInterface { 25 public final class OpenstackRouterInterface {
26 private final String id; 26 private final String id;
...@@ -37,9 +37,9 @@ public final class OpenstackRouterInterface { ...@@ -37,9 +37,9 @@ public final class OpenstackRouterInterface {
37 } 37 }
38 38
39 /** 39 /**
40 - * Returns Router Interface ID. 40 + * Returns router interface ID.
41 * 41 *
42 - * @return router interface ID 42 + * @return router interface id
43 */ 43 */
44 public String id() { 44 public String id() {
45 return id; 45 return id;
...@@ -48,7 +48,7 @@ public final class OpenstackRouterInterface { ...@@ -48,7 +48,7 @@ public final class OpenstackRouterInterface {
48 /** 48 /**
49 * Returns tenant ID. 49 * Returns tenant ID.
50 * 50 *
51 - * @return tenant ID 51 + * @return tenant id
52 */ 52 */
53 public String tenantId() { 53 public String tenantId() {
54 return tenantId; 54 return tenantId;
...@@ -57,7 +57,7 @@ public final class OpenstackRouterInterface { ...@@ -57,7 +57,7 @@ public final class OpenstackRouterInterface {
57 /** 57 /**
58 * Returns subnet ID. 58 * Returns subnet ID.
59 * 59 *
60 - * @return subnet ID 60 + * @return subnet id
61 */ 61 */
62 public String subnetId() { 62 public String subnetId() {
63 return subnetId; 63 return subnetId;
...@@ -66,7 +66,7 @@ public final class OpenstackRouterInterface { ...@@ -66,7 +66,7 @@ public final class OpenstackRouterInterface {
66 /** 66 /**
67 * Returns port ID. 67 * Returns port ID.
68 * 68 *
69 - * @return port ID 69 + * @return port id
70 */ 70 */
71 public String portId() { 71 public String portId() {
72 return portId; 72 return portId;
...@@ -96,7 +96,16 @@ public final class OpenstackRouterInterface { ...@@ -96,7 +96,16 @@ public final class OpenstackRouterInterface {
96 } 96 }
97 97
98 /** 98 /**
99 - * An Openstack Router Interface Builder class. 99 + * Returns OpenStack router interface builder.
100 + *
101 + * @return openstack router interface builder
102 + */
103 + public static Builder builder() {
104 + return new Builder();
105 + }
106 +
107 + /**
108 + * An OpenStack Router interface builder class.
100 */ 109 */
101 public static final class Builder { 110 public static final class Builder {
102 private String id; 111 private String id;
...@@ -105,10 +114,10 @@ public final class OpenstackRouterInterface { ...@@ -105,10 +114,10 @@ public final class OpenstackRouterInterface {
105 private String portId; 114 private String portId;
106 115
107 /** 116 /**
108 - * Sets Router Interface ID. 117 + * Sets router interface ID.
109 * 118 *
110 - * @param id router interface ID 119 + * @param id router interface id
111 - * @return Builder object 120 + * @return builder object
112 */ 121 */
113 public Builder id(String id) { 122 public Builder id(String id) {
114 this.id = id; 123 this.id = id;
...@@ -119,7 +128,7 @@ public final class OpenstackRouterInterface { ...@@ -119,7 +128,7 @@ public final class OpenstackRouterInterface {
119 * Sets tenant ID. 128 * Sets tenant ID.
120 * 129 *
121 * @param tenantId tenant ID 130 * @param tenantId tenant ID
122 - * @return Builder object 131 + * @return builder object
123 */ 132 */
124 public Builder tenantId(String tenantId) { 133 public Builder tenantId(String tenantId) {
125 this.tenantId = tenantId; 134 this.tenantId = tenantId;
...@@ -130,7 +139,7 @@ public final class OpenstackRouterInterface { ...@@ -130,7 +139,7 @@ public final class OpenstackRouterInterface {
130 * Sets subnet ID. 139 * Sets subnet ID.
131 * 140 *
132 * @param subnetId subnet ID 141 * @param subnetId subnet ID
133 - * @return Builder object 142 + * @return builder object
134 */ 143 */
135 public Builder subnetId(String subnetId) { 144 public Builder subnetId(String subnetId) {
136 this.subnetId = subnetId; 145 this.subnetId = subnetId;
...@@ -141,7 +150,7 @@ public final class OpenstackRouterInterface { ...@@ -141,7 +150,7 @@ public final class OpenstackRouterInterface {
141 * Sets port ID. 150 * Sets port ID.
142 * 151 *
143 * @param portId port ID 152 * @param portId port ID
144 - * @return Builder object 153 + * @return builder object
145 */ 154 */
146 public Builder portId(String portId) { 155 public Builder portId(String portId) {
147 this.portId = portId; 156 this.portId = portId;
...@@ -149,14 +158,13 @@ public final class OpenstackRouterInterface { ...@@ -149,14 +158,13 @@ public final class OpenstackRouterInterface {
149 } 158 }
150 159
151 /** 160 /**
152 - * Builds an Openstack Router Interface object. 161 + * Builds an OpenStack router interface object.
153 * 162 *
154 - * @return OpenstackRouterInterface object 163 + * @return openstack router interface object
155 */ 164 */
156 public OpenstackRouterInterface build() { 165 public OpenstackRouterInterface build() {
157 return new OpenstackRouterInterface(checkNotNull(id), checkNotNull(tenantId), 166 return new OpenstackRouterInterface(checkNotNull(id), checkNotNull(tenantId),
158 checkNotNull(subnetId), checkNotNull(portId)); 167 checkNotNull(subnetId), checkNotNull(portId));
159 } 168 }
160 -
161 } 169 }
162 } 170 }
......
...@@ -13,20 +13,18 @@ ...@@ -13,20 +13,18 @@
13 * See the License for the specific language governing permissions and 13 * See the License for the specific language governing permissions and
14 * limitations under the License. 14 * limitations under the License.
15 */ 15 */
16 -package org.onosproject.openstacknetworking.switching; 16 +package org.onosproject.openstacknetworking;
17 17
18 import org.onlab.osgi.DefaultServiceDirectory; 18 import org.onlab.osgi.DefaultServiceDirectory;
19 import org.onlab.osgi.ServiceDirectory; 19 import org.onlab.osgi.ServiceDirectory;
20 import org.onlab.packet.Ip4Address; 20 import org.onlab.packet.Ip4Address;
21 import org.onlab.util.Tools; 21 import org.onlab.util.Tools;
22 -import org.onosproject.core.ApplicationId;
23 import org.onosproject.core.CoreService; 22 import org.onosproject.core.CoreService;
24 import org.onosproject.mastership.MastershipService; 23 import org.onosproject.mastership.MastershipService;
25 import org.onosproject.net.Host; 24 import org.onosproject.net.Host;
26 import org.onosproject.net.host.HostEvent; 25 import org.onosproject.net.host.HostEvent;
27 import org.onosproject.net.host.HostListener; 26 import org.onosproject.net.host.HostListener;
28 import org.onosproject.net.host.HostService; 27 import org.onosproject.net.host.HostService;
29 -import org.onosproject.openstacknetworking.Constants;
30 import org.slf4j.Logger; 28 import org.slf4j.Logger;
31 29
32 import java.util.Objects; 30 import java.util.Objects;
...@@ -53,7 +51,6 @@ public abstract class AbstractVmHandler { ...@@ -53,7 +51,6 @@ public abstract class AbstractVmHandler {
53 protected MastershipService mastershipService; 51 protected MastershipService mastershipService;
54 protected HostService hostService; 52 protected HostService hostService;
55 53
56 - protected ApplicationId appId;
57 protected HostListener hostListener = new InternalHostListener(); 54 protected HostListener hostListener = new InternalHostListener();
58 55
59 protected void activate() { 56 protected void activate() {
...@@ -61,8 +58,6 @@ public abstract class AbstractVmHandler { ...@@ -61,8 +58,6 @@ public abstract class AbstractVmHandler {
61 coreService = services.get(CoreService.class); 58 coreService = services.get(CoreService.class);
62 mastershipService = services.get(MastershipService.class); 59 mastershipService = services.get(MastershipService.class);
63 hostService = services.get(HostService.class); 60 hostService = services.get(HostService.class);
64 -
65 - appId = coreService.registerApplication(Constants.APP_ID);
66 hostService.addListener(hostListener); 61 hostService.addListener(hostListener);
67 62
68 log.info("Started"); 63 log.info("Started");
...@@ -75,9 +70,19 @@ public abstract class AbstractVmHandler { ...@@ -75,9 +70,19 @@ public abstract class AbstractVmHandler {
75 log.info("Stopped"); 70 log.info("Stopped");
76 } 71 }
77 72
78 - abstract void hostDetected(Host host); 73 + /**
79 - 74 + * Performs any action when a host is detected.
80 - abstract void hostRemoved(Host host); 75 + *
76 + * @param host detected host
77 + */
78 + protected abstract void hostDetected(Host host);
79 +
80 + /**
81 + * Performs any action when a host is removed.
82 + *
83 + * @param host removed host
84 + */
85 + protected abstract void hostRemoved(Host host);
81 86
82 protected boolean isValidHost(Host host) { 87 protected boolean isValidHost(Host host) {
83 return !host.ipAddresses().isEmpty() && 88 return !host.ipAddresses().isEmpty() &&
......
...@@ -28,23 +28,27 @@ public final class Constants { ...@@ -28,23 +28,27 @@ public final class Constants {
28 private Constants() { 28 private Constants() {
29 } 29 }
30 30
31 - public static final String APP_ID = "org.onosproject.openstackswitching"; 31 + public static final String SWITCHING_APP_ID = "org.onosproject.openstackswitching";
32 + public static final String ROUTING_APP_ID = "org.onosproject.openstackrouting";
32 33
33 - public static final String PORTNAME_PREFIX_VM = "tap"; 34 + public static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
34 - public static final String PORTNAME_PREFIX_ROUTER = "qr-"; 35 + public static final String DEVICE_OWNER_ROUTER_GATEWAY = "network:router_gateway";
35 - public static final String PORTNAME_PREFIX_TUNNEL = "vxlan"; 36 + public static final String DEVICE_OWNER_FLOATING_IP = "network:floatingip";
36 37
37 - public static final MacAddress GATEWAY_MAC = MacAddress.valueOf("1f:1f:1f:1f:1f:1f"); 38 + public static final String PORT_NAME_PREFIX_VM = "tap";
39 + public static final String PORT_NAME_PREFIX_TUNNEL = "vxlan";
38 40
39 - // TODO: Please change these valuses following the way vrouter is implemented 41 + public static final String DEFAULT_GATEWAY_MAC_STR = "fe:00:00:00:00:02";
40 - public static final MacAddress GW_EXT_INT_MAC = MacAddress.valueOf("56:e6:30:a6:8c:e5"); 42 + public static final MacAddress DEFAULT_GATEWAY_MAC = MacAddress.valueOf(DEFAULT_GATEWAY_MAC_STR);
41 - public static final MacAddress PHY_ROUTER_MAC = MacAddress.valueOf("00:00:00:00:01:01"); 43 + // TODO make this configurable
44 + public static final MacAddress DEFAULT_EXTERNAL_ROUTER_MAC = MacAddress.valueOf("fe:00:00:00:00:01");
42 45
43 public static final Ip4Address DNS_SERVER_IP = Ip4Address.valueOf("8.8.8.8"); 46 public static final Ip4Address DNS_SERVER_IP = Ip4Address.valueOf("8.8.8.8");
44 public static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0"); 47 public static final IpPrefix IP_PREFIX_ANY = Ip4Prefix.valueOf("0.0.0.0/0");
45 public static final int DHCP_INFINITE_LEASE = -1; 48 public static final int DHCP_INFINITE_LEASE = -1;
46 49
47 public static final String NETWORK_ID = "networkId"; 50 public static final String NETWORK_ID = "networkId";
51 + public static final String SUBNET_ID = "subnetId";
48 public static final String PORT_ID = "portId"; 52 public static final String PORT_ID = "portId";
49 public static final String VXLAN_ID = "vxlanId"; 53 public static final String VXLAN_ID = "vxlanId";
50 public static final String TENANT_ID = "tenantId"; 54 public static final String TENANT_ID = "tenantId";
...@@ -55,4 +59,8 @@ public final class Constants { ...@@ -55,4 +59,8 @@ public final class Constants {
55 public static final int TUNNELTAG_RULE_PRIORITY = 30000; 59 public static final int TUNNELTAG_RULE_PRIORITY = 30000;
56 public static final int ACL_RULE_PRIORITY = 30000; 60 public static final int ACL_RULE_PRIORITY = 30000;
57 61
62 + public static final int ROUTING_RULE_PRIORITY = 25000;
63 + public static final int FLOATING_RULE_PRIORITY = 42000;
64 + public static final int PNAT_RULE_PRIORITY = 26000;
65 + public static final int PNAT_TIMEOUT = 120;
58 } 66 }
...\ No newline at end of file ...\ No newline at end of file
......
1 +/*
2 + * Copyright 2016-present 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 +package org.onosproject.openstacknetworking;
17 +
18 +import org.onosproject.openstackinterface.OpenstackFloatingIP;
19 +
20 +/**
21 + * Handles floating IP update requests from OpenStack.
22 + */
23 +public interface OpenstackFloatingIpService {
24 +
25 + enum Action {
26 + ASSOCIATE,
27 + DISSASSOCIATE
28 + }
29 +
30 + /**
31 + * Handles floating IP create request from OpenStack.
32 + *
33 + * @param floatingIp floating IP information
34 + */
35 + void createFloatingIp(OpenstackFloatingIP floatingIp);
36 +
37 + /**
38 + * Handles floating IP update request from OpenStack.
39 + *
40 + * @param floatingIp floating IP information
41 + */
42 + void updateFloatingIp(OpenstackFloatingIP floatingIp);
43 +
44 + /**
45 + * Handles floating IP remove request from OpenStack.
46 + *
47 + * @param floatingIpId floating ip identifier
48 + */
49 + void deleteFloatingIp(String floatingIpId);
50 +}
...@@ -15,76 +15,49 @@ ...@@ -15,76 +15,49 @@
15 */ 15 */
16 package org.onosproject.openstacknetworking; 16 package org.onosproject.openstacknetworking;
17 17
18 -import org.onosproject.openstackinterface.OpenstackFloatingIP;
19 import org.onosproject.openstackinterface.OpenstackRouter; 18 import org.onosproject.openstackinterface.OpenstackRouter;
20 import org.onosproject.openstackinterface.OpenstackRouterInterface; 19 import org.onosproject.openstackinterface.OpenstackRouterInterface;
21 20
22 /** 21 /**
23 - * Supports L3 management REST API for openstack. 22 + * Handles router update requests from OpenStack.
24 */ 23 */
25 public interface OpenstackRoutingService { 24 public interface OpenstackRoutingService {
26 25
27 /** 26 /**
28 - * Stores the floating IP information created by openstack. 27 + * Handles the router create request from OpenStack.
29 * 28 *
30 - * @param openstackFloatingIp Floating IP information 29 + * @param osRouter router information
31 */ 30 */
32 - void createFloatingIP(OpenstackFloatingIP openstackFloatingIp); 31 + void createRouter(OpenstackRouter osRouter);
33 32
34 /** 33 /**
35 - * Updates flow rules corresponding to the floating IP information updated by openstack. 34 + * Handles the router update request from OpenStack.
35 + * Update router is called when the name, administrative state, or the external
36 + * gateway setting is updated. The external gateway update is the only case
37 + * that openstack routing service cares.
36 * 38 *
37 - * @param openstackFloatingIp Floating IP information 39 + * @param osRouter router information
38 */ 40 */
39 - void updateFloatingIP(OpenstackFloatingIP openstackFloatingIp); 41 + void updateRouter(OpenstackRouter osRouter);
40 42
41 /** 43 /**
42 - * Removes flow rules corresponding to floating IP information removed by openstack. 44 + * Handles the router remove request from OpenStack.
43 * 45 *
44 - * @param id Deleted Floating IP`s ID 46 + * @param osRouterId identifier of the router
45 */ 47 */
46 - void deleteFloatingIP(String id); 48 + void removeRouter(String osRouterId);
47 49
48 /** 50 /**
49 - * Stores the router information created by openstack. 51 + * Handles router interface add request from OpenStack.
50 * 52 *
51 - * @param openstackRouter Router information 53 + * @param osInterface router interface information
52 */ 54 */
53 - void createRouter(OpenstackRouter openstackRouter); 55 + void addRouterInterface(OpenstackRouterInterface osInterface);
54 56
55 /** 57 /**
56 - * Updates flow rules corresponding to the router information updated by openstack. 58 + * Handles router interface remove request from OpenStack.
57 * 59 *
58 - * @param openstackRouter Router information 60 + * @param osInterface router interface information
59 */ 61 */
60 - void updateRouter(OpenstackRouter openstackRouter); 62 + void removeRouterInterface(OpenstackRouterInterface osInterface);
61 -
62 - /**
63 - * Removes flow rules corresponding to the router information removed by openstack.
64 - *
65 - * @param id Deleted router`s ID
66 - */
67 - void deleteRouter(String id);
68 -
69 - /**
70 - * Updates flow rules corresponding to the router information updated by openstack.
71 - *
72 - * @param openstackRouterInterface Router interface information
73 - */
74 - void updateRouterInterface(OpenstackRouterInterface openstackRouterInterface);
75 -
76 - /**
77 - * Removes flow rules corresponding to the router information removed by openstack.
78 - *
79 - * @param openstackRouterInterface Router interface information
80 - */
81 - void removeRouterInterface(OpenstackRouterInterface openstackRouterInterface);
82 -
83 - /**
84 - * Returns network id for routerInterface.
85 - *
86 - * @param portId routerInterface`s port id
87 - * @return network id
88 - */
89 - String networkIdForRouterInterface(String portId);
90 } 63 }
......
1 +/*
2 + * Copyright 2016-present 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 +package org.onosproject.openstacknetworking;
17 +
18 +import org.onlab.packet.Ip4Address;
19 +import org.onosproject.core.ApplicationId;
20 +import org.onosproject.net.Device;
21 +import org.onosproject.net.DeviceId;
22 +import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
23 +import org.onosproject.net.device.DeviceService;
24 +import org.onosproject.net.flow.DefaultTrafficTreatment;
25 +import org.onosproject.net.flow.TrafficSelector;
26 +import org.onosproject.net.flow.instructions.ExtensionPropertyException;
27 +import org.onosproject.net.flow.instructions.ExtensionTreatment;
28 +import org.onosproject.net.flowobjective.DefaultForwardingObjective;
29 +import org.onosproject.net.flowobjective.FlowObjectiveService;
30 +import org.onosproject.net.flowobjective.ForwardingObjective;
31 +import org.slf4j.Logger;
32 +
33 +import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
34 +import static org.slf4j.LoggerFactory.getLogger;
35 +
36 +/**
37 + * Provides common methods to help populating flow rules for SONA applications.
38 + */
39 +public final class RulePopulatorUtil {
40 +
41 + protected static final Logger log = getLogger(RulePopulatorUtil.class);
42 +
43 + private static final String TUNNEL_DST = "tunnelDst";
44 +
45 + private RulePopulatorUtil() {
46 + }
47 +
48 + /**
49 + * Returns tunnel destination extension treatment object.
50 + *
51 + * @param deviceService driver service
52 + * @param deviceId device id to apply this treatment
53 + * @param remoteIp tunnel destination ip address
54 + * @return extension treatment
55 + */
56 + public static ExtensionTreatment buildExtension(DeviceService deviceService,
57 + DeviceId deviceId,
58 + Ip4Address remoteIp) {
59 + Device device = deviceService.getDevice(deviceId);
60 + if (device != null && !device.is(ExtensionTreatmentResolver.class)) {
61 + log.error("The extension treatment is not supported");
62 + return null;
63 + }
64 +
65 + ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
66 + ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
67 + try {
68 + treatment.setPropertyValue(TUNNEL_DST, remoteIp);
69 + return treatment;
70 + } catch (ExtensionPropertyException e) {
71 + log.warn("Failed to get tunnelDst extension treatment for {}", deviceId);
72 + return null;
73 + }
74 + }
75 +
76 + /**
77 + * Removes flow rules with the supplied information.
78 + *
79 + * @param flowObjectiveService flow objective service
80 + * @param appId application id
81 + * @param deviceId device id to remove this flow rule
82 + * @param selector traffic selector
83 + * @param flag flag
84 + * @param priority priority
85 + */
86 + public static void removeRule(FlowObjectiveService flowObjectiveService,
87 + ApplicationId appId,
88 + DeviceId deviceId,
89 + TrafficSelector selector,
90 + ForwardingObjective.Flag flag,
91 + int priority) {
92 + ForwardingObjective fo = DefaultForwardingObjective.builder()
93 + .withSelector(selector)
94 + .withTreatment(DefaultTrafficTreatment.builder().build())
95 + .withFlag(flag)
96 + .withPriority(priority)
97 + .fromApp(appId)
98 + .remove();
99 +
100 + flowObjectiveService.forward(deviceId, fo);
101 + }
102 +}
1 -/*
2 - * Copyright 2016-present 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 -package org.onosproject.openstacknetworking.routing;
17 -
18 -import org.onosproject.net.Host;
19 -import org.onosproject.openstackinterface.OpenstackFloatingIP;
20 -
21 -/**
22 - * Handle FloatingIP Event for Managing Flow Rules In Openstack Nodes.
23 - */
24 -public class OpenstackFloatingIPHandler implements Runnable {
25 -
26 - public enum Action {
27 - ASSOCIATE,
28 - DISSASSOCIATE
29 - }
30 -
31 - private final OpenstackFloatingIP floatingIP;
32 - private final OpenstackRoutingRulePopulator rulePopulator;
33 - private final Host host;
34 - private final Action action;
35 -
36 -
37 - OpenstackFloatingIPHandler(OpenstackRoutingRulePopulator rulePopulator,
38 - OpenstackFloatingIP openstackFloatingIP, Action action, Host host) {
39 - this.floatingIP = openstackFloatingIP;
40 - this.rulePopulator = rulePopulator;
41 - this.action = action;
42 - this.host = host;
43 - }
44 -
45 - @Override
46 - public void run() {
47 - if (action == Action.ASSOCIATE) {
48 - rulePopulator.populateFloatingIpRules(floatingIP);
49 - } else {
50 - rulePopulator.removeFloatingIpRules(floatingIP, host);
51 - }
52 - }
53 -}
1 +/*
2 + * Copyright 2016-present 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 +package org.onosproject.openstacknetworking.routing;
17 +
18 +import com.google.common.base.Strings;
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
24 +import org.apache.felix.scr.annotations.Service;
25 +import org.onlab.packet.Ethernet;
26 +import org.onlab.packet.IpAddress;
27 +import org.onlab.util.KryoNamespace;
28 +import org.onlab.util.Tools;
29 +import org.onosproject.core.ApplicationId;
30 +import org.onosproject.core.CoreService;
31 +import org.onosproject.net.DeviceId;
32 +import org.onosproject.net.Host;
33 +import org.onosproject.net.device.DeviceService;
34 +import org.onosproject.net.flow.DefaultTrafficSelector;
35 +import org.onosproject.net.flow.DefaultTrafficTreatment;
36 +import org.onosproject.net.flow.TrafficSelector;
37 +import org.onosproject.net.flow.TrafficTreatment;
38 +import org.onosproject.net.flowobjective.DefaultForwardingObjective;
39 +import org.onosproject.net.flowobjective.FlowObjectiveService;
40 +import org.onosproject.net.flowobjective.ForwardingObjective;
41 +import org.onosproject.net.host.HostService;
42 +import org.onosproject.openstackinterface.OpenstackFloatingIP;
43 +import org.onosproject.openstacknetworking.Constants;
44 +import org.onosproject.openstacknetworking.OpenstackFloatingIpService;
45 +import org.onosproject.openstacknetworking.RulePopulatorUtil;
46 +import org.onosproject.openstacknode.OpenstackNode;
47 +import org.onosproject.openstacknode.OpenstackNodeEvent;
48 +import org.onosproject.openstacknode.OpenstackNodeListener;
49 +import org.onosproject.openstacknode.OpenstackNodeService;
50 +import org.onosproject.scalablegateway.api.GatewayNode;
51 +import org.onosproject.scalablegateway.api.ScalableGatewayService;
52 +import org.onosproject.store.serializers.KryoNamespaces;
53 +import org.onosproject.store.service.ConsistentMap;
54 +import org.onosproject.store.service.Serializer;
55 +import org.onosproject.store.service.StorageService;
56 +import org.onosproject.store.service.Versioned;
57 +import org.slf4j.Logger;
58 +import org.slf4j.LoggerFactory;
59 +
60 +import java.util.Objects;
61 +import java.util.Optional;
62 +import java.util.concurrent.ExecutorService;
63 +
64 +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
65 +import static org.onlab.util.Tools.groupedThreads;
66 +import static org.onosproject.openstacknetworking.Constants.*;
67 +import static org.onosproject.openstacknetworking.RulePopulatorUtil.buildExtension;
68 +import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
69 +
70 +
71 +@Service
72 +@Component(immediate = true)
73 +public class OpenstackFloatingIpManager implements OpenstackFloatingIpService {
74 +
75 + private final Logger log = LoggerFactory.getLogger(getClass());
76 +
77 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 + protected CoreService coreService;
79 +
80 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
81 + protected HostService hostService;
82 +
83 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 + protected DeviceService deviceService;
85 +
86 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
87 + protected FlowObjectiveService flowObjectiveService;
88 +
89 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 + protected StorageService storageService;
91 +
92 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 + protected OpenstackNodeService nodeService;
94 +
95 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
96 + protected ScalableGatewayService gatewayService;
97 +
98 + private static final String NOT_ASSOCIATED = "null";
99 + private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER =
100 + KryoNamespace.newBuilder().register(KryoNamespaces.API);
101 +
102 + private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
103 + groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
104 + private final InternalNodeListener nodeListener = new InternalNodeListener();
105 + private ConsistentMap<IpAddress, Host> floatingIpMap;
106 +
107 + private ApplicationId appId;
108 +
109 + @Activate
110 + protected void activate() {
111 + appId = coreService.registerApplication(ROUTING_APP_ID);
112 + nodeService.addListener(nodeListener);
113 + floatingIpMap = storageService.<IpAddress, Host>consistentMapBuilder()
114 + .withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
115 + .withName("openstackrouting-floatingip")
116 + .withApplicationId(appId)
117 + .build();
118 +
119 + log.info("Started");
120 + }
121 +
122 + @Deactivate
123 + protected void deactivate() {
124 + nodeService.removeListener(nodeListener);
125 + log.info("Stopped");
126 + }
127 +
128 + @Override
129 + public void createFloatingIp(OpenstackFloatingIP floatingIp) {
130 + }
131 +
132 + @Override
133 + public void updateFloatingIp(OpenstackFloatingIP floatingIp) {
134 + if (Strings.isNullOrEmpty(floatingIp.portId()) ||
135 + floatingIp.portId().equals(NOT_ASSOCIATED)) {
136 + eventExecutor.execute(() -> disassociateFloatingIp(floatingIp));
137 + } else {
138 + eventExecutor.execute(() -> associateFloatingIp(floatingIp));
139 + }
140 + }
141 +
142 + @Override
143 + public void deleteFloatingIp(String floatingIpId) {
144 + }
145 +
146 + private void associateFloatingIp(OpenstackFloatingIP floatingIp) {
147 + Optional<Host> associatedVm = Tools.stream(hostService.getHosts())
148 + .filter(host -> Objects.equals(
149 + host.annotations().value(PORT_ID),
150 + floatingIp.portId()))
151 + .findAny();
152 + if (!associatedVm.isPresent()) {
153 + log.warn("Failed to associate floating IP({}) to port:{}",
154 + floatingIp.floatingIpAddress(),
155 + floatingIp.portId());
156 + return;
157 + }
158 +
159 + floatingIpMap.put(floatingIp.floatingIpAddress(), associatedVm.get());
160 + populateFloatingIpRules(floatingIp.floatingIpAddress(), associatedVm.get());
161 +
162 + log.info("Associated floating IP {} to fixed IP {}",
163 + floatingIp.floatingIpAddress(), floatingIp.fixedIpAddress());
164 + }
165 +
166 + private void disassociateFloatingIp(OpenstackFloatingIP floatingIp) {
167 + Versioned<Host> associatedVm = floatingIpMap.remove(floatingIp.floatingIpAddress());
168 + if (associatedVm == null) {
169 + log.warn("Failed to disassociate floating IP({})",
170 + floatingIp.floatingIpAddress());
171 + // No VM is actually associated with the floating IP, do nothing
172 + return;
173 + }
174 +
175 + removeFloatingIpRules(floatingIp.floatingIpAddress(), associatedVm.value());
176 + log.info("Disassociated floating IP {} from fixed IP {}",
177 + floatingIp.floatingIpAddress(),
178 + associatedVm.value().ipAddresses());
179 + }
180 +
181 + private void populateFloatingIpRules(IpAddress floatingIp, Host associatedVm) {
182 + populateFloatingIpIncomingRules(floatingIp, associatedVm);
183 + populateFloatingIpOutgoingRules(floatingIp, associatedVm);
184 + }
185 +
186 + private void removeFloatingIpRules(IpAddress floatingIp, Host associatedVm) {
187 + Optional<IpAddress> fixedIp = associatedVm.ipAddresses().stream().findFirst();
188 + if (!fixedIp.isPresent()) {
189 + log.warn("Failed to remove floating IP({}) from {}",
190 + floatingIp, associatedVm);
191 + return;
192 + }
193 +
194 + TrafficSelector.Builder sOutgoingBuilder = DefaultTrafficSelector.builder();
195 + TrafficSelector.Builder sIncomingBuilder = DefaultTrafficSelector.builder();
196 +
197 + sOutgoingBuilder.matchEthType(Ethernet.TYPE_IPV4)
198 + .matchTunnelId(Long.valueOf(associatedVm.annotations().value(VXLAN_ID)))
199 + .matchIPSrc(fixedIp.get().toIpPrefix());
200 +
201 + sIncomingBuilder.matchEthType(Ethernet.TYPE_IPV4)
202 + .matchIPDst(floatingIp.toIpPrefix());
203 +
204 + gatewayService.getGatewayDeviceIds().stream().forEach(deviceId -> {
205 + RulePopulatorUtil.removeRule(
206 + flowObjectiveService,
207 + appId,
208 + deviceId,
209 + sOutgoingBuilder.build(),
210 + ForwardingObjective.Flag.VERSATILE,
211 + FLOATING_RULE_PRIORITY);
212 +
213 + RulePopulatorUtil.removeRule(
214 + flowObjectiveService,
215 + appId,
216 + deviceId,
217 + sIncomingBuilder.build(),
218 + ForwardingObjective.Flag.VERSATILE,
219 + FLOATING_RULE_PRIORITY);
220 + });
221 + }
222 +
223 + private void populateFloatingIpIncomingRules(IpAddress floatingIp, Host associatedVm) {
224 + DeviceId cnodeId = associatedVm.location().deviceId();
225 + Optional<IpAddress> dataIp = nodeService.dataIp(cnodeId);
226 + Optional<IpAddress> fixedIp = associatedVm.ipAddresses().stream().findFirst();
227 +
228 + if (!fixedIp.isPresent() || !dataIp.isPresent()) {
229 + log.warn("Failed to associate floating IP({})", floatingIp);
230 + return;
231 + }
232 +
233 + TrafficSelector selector = DefaultTrafficSelector.builder()
234 + .matchEthType(Ethernet.TYPE_IPV4)
235 + .matchIPDst(floatingIp.toIpPrefix())
236 + .build();
237 +
238 + gatewayService.getGatewayDeviceIds().stream().forEach(gnodeId -> {
239 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
240 + .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
241 + .setEthDst(associatedVm.mac())
242 + .setIpDst(associatedVm.ipAddresses().stream().findFirst().get())
243 + .setTunnelId(Long.valueOf(associatedVm.annotations().value(VXLAN_ID)))
244 + .extension(buildExtension(deviceService, cnodeId, dataIp.get().getIp4Address()),
245 + cnodeId)
246 + .setOutput(nodeService.tunnelPort(gnodeId).get())
247 + .build();
248 +
249 + ForwardingObjective fo = DefaultForwardingObjective.builder()
250 + .withSelector(selector)
251 + .withTreatment(treatment)
252 + .withFlag(ForwardingObjective.Flag.VERSATILE)
253 + .withPriority(FLOATING_RULE_PRIORITY)
254 + .fromApp(appId)
255 + .add();
256 +
257 + flowObjectiveService.forward(gnodeId, fo);
258 + });
259 + }
260 +
261 + private void populateFloatingIpOutgoingRules(IpAddress floatingIp, Host associatedVm) {
262 + TrafficSelector selector = DefaultTrafficSelector.builder()
263 + .matchEthType(Ethernet.TYPE_IPV4)
264 + .matchTunnelId(Long.valueOf(associatedVm.annotations().value(VXLAN_ID)))
265 + .matchIPSrc(associatedVm.ipAddresses().stream().findFirst().get().toIpPrefix())
266 + .build();
267 +
268 + gatewayService.getGatewayDeviceIds().stream().forEach(gnodeId -> {
269 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
270 + .setIpSrc(floatingIp)
271 + .setEthSrc(Constants.DEFAULT_GATEWAY_MAC)
272 + .setEthDst(Constants.DEFAULT_EXTERNAL_ROUTER_MAC)
273 + .setOutput(gatewayService.getUplinkPort(gnodeId))
274 + .build();
275 +
276 + ForwardingObjective fo = DefaultForwardingObjective.builder()
277 + .withSelector(selector)
278 + .withTreatment(treatment)
279 + .withFlag(ForwardingObjective.Flag.VERSATILE)
280 + .withPriority(FLOATING_RULE_PRIORITY)
281 + .fromApp(appId)
282 + .add();
283 +
284 + flowObjectiveService.forward(gnodeId, fo);
285 + });
286 + }
287 +
288 + private void reloadFloatingIpRules() {
289 + floatingIpMap.entrySet().stream().forEach(entry -> {
290 + IpAddress floatingIp = entry.getKey();
291 + Host associatedVm = entry.getValue().value();
292 +
293 + populateFloatingIpRules(floatingIp, associatedVm);
294 + log.debug("Reload floating IP {} mapped to {}",
295 + floatingIp, associatedVm.ipAddresses());
296 + });
297 + }
298 +
299 + // TODO apply existing floating IPs on service start-up by handling host event
300 + // TODO consider the case that port with associated floating IP is attached to a VM
301 +
302 + private class InternalNodeListener implements OpenstackNodeListener {
303 +
304 + @Override
305 + public void event(OpenstackNodeEvent event) {
306 + OpenstackNode node = event.node();
307 +
308 + switch (event.type()) {
309 + case COMPLETE:
310 + if (node.type() == GATEWAY) {
311 + log.info("GATEWAY node {} detected", node.hostname());
312 + GatewayNode gnode = GatewayNode.builder()
313 + .gatewayDeviceId(node.intBridge())
314 + .dataIpAddress(node.dataIp().getIp4Address())
315 + .uplinkIntf(node.externalPortName().get())
316 + .build();
317 + gatewayService.addGatewayNode(gnode);
318 + eventExecutor.execute(OpenstackFloatingIpManager.this::reloadFloatingIpRules);
319 + }
320 + break;
321 + case INIT:
322 + case DEVICE_CREATED:
323 + case INCOMPLETE:
324 + default:
325 + break;
326 + }
327 + }
328 + }
329 +}
...@@ -16,322 +16,319 @@ ...@@ -16,322 +16,319 @@
16 package org.onosproject.openstacknetworking.routing; 16 package org.onosproject.openstacknetworking.routing;
17 17
18 import com.google.common.collect.Maps; 18 import com.google.common.collect.Maps;
19 +import org.apache.felix.scr.annotations.Activate;
20 +import org.apache.felix.scr.annotations.Component;
21 +import org.apache.felix.scr.annotations.Deactivate;
22 +import org.apache.felix.scr.annotations.Reference;
23 +import org.apache.felix.scr.annotations.ReferenceCardinality;
19 import org.onlab.packet.Ethernet; 24 import org.onlab.packet.Ethernet;
20 import org.onlab.packet.ICMP; 25 import org.onlab.packet.ICMP;
21 import org.onlab.packet.IPv4; 26 import org.onlab.packet.IPv4;
22 import org.onlab.packet.Ip4Address; 27 import org.onlab.packet.Ip4Address;
23 -import org.onlab.packet.IpAddress;
24 -import org.onlab.packet.MacAddress;
25 import org.onosproject.core.ApplicationId; 28 import org.onosproject.core.ApplicationId;
29 +import org.onosproject.core.CoreService;
26 import org.onosproject.net.DeviceId; 30 import org.onosproject.net.DeviceId;
27 import org.onosproject.net.Host; 31 import org.onosproject.net.Host;
28 -import org.onosproject.net.Port;
29 -import org.onosproject.net.PortNumber;
30 -import org.onosproject.net.device.DeviceService;
31 import org.onosproject.net.flow.DefaultTrafficSelector; 32 import org.onosproject.net.flow.DefaultTrafficSelector;
32 import org.onosproject.net.flow.DefaultTrafficTreatment; 33 import org.onosproject.net.flow.DefaultTrafficTreatment;
33 import org.onosproject.net.flow.TrafficSelector; 34 import org.onosproject.net.flow.TrafficSelector;
34 import org.onosproject.net.flow.TrafficTreatment; 35 import org.onosproject.net.flow.TrafficTreatment;
35 import org.onosproject.net.host.HostService; 36 import org.onosproject.net.host.HostService;
36 import org.onosproject.net.packet.DefaultOutboundPacket; 37 import org.onosproject.net.packet.DefaultOutboundPacket;
38 +import org.onosproject.net.packet.InboundPacket;
37 import org.onosproject.net.packet.OutboundPacket; 39 import org.onosproject.net.packet.OutboundPacket;
38 import org.onosproject.net.packet.PacketContext; 40 import org.onosproject.net.packet.PacketContext;
39 import org.onosproject.net.packet.PacketPriority; 41 import org.onosproject.net.packet.PacketPriority;
42 +import org.onosproject.net.packet.PacketProcessor;
40 import org.onosproject.net.packet.PacketService; 43 import org.onosproject.net.packet.PacketService;
44 +import org.onosproject.openstackinterface.OpenstackRouter;
41 import org.onosproject.openstacknetworking.Constants; 45 import org.onosproject.openstacknetworking.Constants;
42 import org.onosproject.openstackinterface.OpenstackInterfaceService; 46 import org.onosproject.openstackinterface.OpenstackInterfaceService;
43 import org.onosproject.openstackinterface.OpenstackPort; 47 import org.onosproject.openstackinterface.OpenstackPort;
44 import org.onosproject.openstacknode.OpenstackNode; 48 import org.onosproject.openstacknode.OpenstackNode;
49 +import org.onosproject.openstacknode.OpenstackNodeEvent;
50 +import org.onosproject.openstacknode.OpenstackNodeListener;
45 import org.onosproject.openstacknode.OpenstackNodeService; 51 import org.onosproject.openstacknode.OpenstackNodeService;
46 import org.onosproject.scalablegateway.api.ScalableGatewayService; 52 import org.onosproject.scalablegateway.api.ScalableGatewayService;
47 import org.slf4j.Logger; 53 import org.slf4j.Logger;
48 54
49 import java.nio.ByteBuffer; 55 import java.nio.ByteBuffer;
50 import java.util.Map; 56 import java.util.Map;
57 +import java.util.Objects;
51 import java.util.Optional; 58 import java.util.Optional;
59 +import java.util.concurrent.ExecutorService;
52 60
53 -import static com.google.common.base.Preconditions.checkNotNull; 61 +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
54 - 62 +import static org.onlab.util.Tools.groupedThreads;
63 +import static org.onosproject.openstacknetworking.Constants.*;
64 +import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
55 import static org.slf4j.LoggerFactory.getLogger; 65 import static org.slf4j.LoggerFactory.getLogger;
56 66
57 67
58 /** 68 /**
59 - * Handle ICMP packet sent from Openstack Gateway nodes. 69 + * Handle ICMP packet sent from OpenStack Gateway nodes.
70 + * For a request to any private network gateway IPs, it generates fake reply.
71 + * For a request to the external network, it does source NAT with a public IP and
72 + * forward the request to the external only if the request instance has external
73 + * connection setups.
60 */ 74 */
75 +@Component(immediate = true)
61 public class OpenstackIcmpHandler { 76 public class OpenstackIcmpHandler {
62 protected final Logger log = getLogger(getClass()); 77 protected final Logger log = getLogger(getClass());
63 78
79 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 + protected CoreService coreService;
81 +
82 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 + protected PacketService packetService;
84 +
85 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 + protected HostService hostService;
87 +
88 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 + protected OpenstackInterfaceService openstackService;
64 90
65 - private static final String NETWORK_ROUTER_INTERFACE = "network:router_interface"; 91 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 - private static final String PORTNAME = "portName"; 92 + protected ScalableGatewayService gatewayService;
67 - private static final String NETWORK_ROUTER_GATEWAY = "network:router_gateway";
68 - private static final String NETWORK_FLOATING_IP = "network:floatingip";
69 93
70 - private final PacketService packetService; 94 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
71 - private final DeviceService deviceService; 95 + protected OpenstackNodeService nodeService;
72 - private final ScalableGatewayService gatewayService; 96 +
73 - private final HostService hostService; 97 + private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
98 + groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
99 + private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
100 + private final InternalNodeListener nodeListener = new InternalNodeListener();
74 private final Map<String, Host> icmpInfoMap = Maps.newHashMap(); 101 private final Map<String, Host> icmpInfoMap = Maps.newHashMap();
75 - private final OpenstackInterfaceService openstackService; 102 +
76 - private final OpenstackNodeService nodeService; 103 + ApplicationId appId;
77 - 104 +
78 - /** 105 + @Activate
79 - * Default constructor. 106 + protected void activate() {
80 - * 107 + appId = coreService.registerApplication(ROUTING_APP_ID);
81 - * @param packetService packet service 108 + packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
82 - * @param deviceService device service 109 + nodeService.addListener(nodeListener);
83 - * @param openstackService openstackInterface service 110 + requestPacket(appId);
84 - */ 111 +
85 - OpenstackIcmpHandler(PacketService packetService, 112 + log.info("Started");
86 - DeviceService deviceService,
87 - HostService hostService,
88 - OpenstackInterfaceService openstackService,
89 - OpenstackNodeService nodeService,
90 - ScalableGatewayService gatewayService
91 - ) {
92 - this.packetService = packetService;
93 - this.deviceService = deviceService;
94 - this.hostService = hostService;
95 - this.openstackService = checkNotNull(openstackService);
96 - this.nodeService = nodeService;
97 - this.gatewayService = gatewayService;
98 } 113 }
99 114
100 - /** 115 + @Deactivate
101 - * Requests ICMP packet. 116 + protected void deactivate() {
102 - * 117 + packetService.removeProcessor(packetProcessor);
103 - * @param appId Application Id 118 + log.info("Stopped");
104 - */ 119 + }
105 - public void requestPacket(ApplicationId appId) { 120 +
121 + private void requestPacket(ApplicationId appId) {
106 TrafficSelector icmpSelector = DefaultTrafficSelector.builder() 122 TrafficSelector icmpSelector = DefaultTrafficSelector.builder()
107 .matchEthType(Ethernet.TYPE_IPV4) 123 .matchEthType(Ethernet.TYPE_IPV4)
108 .matchIPProtocol(IPv4.PROTOCOL_ICMP) 124 .matchIPProtocol(IPv4.PROTOCOL_ICMP)
109 .build(); 125 .build();
110 126
111 - // TODO: Return the correct gateway node 127 + gatewayService.getGatewayDeviceIds().stream().forEach(gateway -> {
112 - Optional<OpenstackNode> gwNode = nodeService.nodes().stream() 128 + packetService.requestPackets(icmpSelector,
113 - .filter(n -> n.type().equals(OpenstackNodeService.NodeType.GATEWAY)) 129 + PacketPriority.CONTROL,
114 - .findFirst(); 130 + appId,
115 - 131 + Optional.of(gateway));
116 - if (!gwNode.isPresent()) { 132 + log.debug("Requested ICMP packet on {}", gateway);
117 - log.warn("No Gateway is defined."); 133 + });
118 - return;
119 - }
120 -
121 - packetService.requestPackets(icmpSelector,
122 - PacketPriority.CONTROL,
123 - appId,
124 - Optional.of(gwNode.get().intBridge()));
125 } 134 }
126 135
127 - /** 136 + private void processIcmpPacket(PacketContext context, Ethernet ethernet) {
128 - * Handles ICMP packet.
129 - *
130 - * @param context packet context
131 - * @param ethernet ethernet
132 - */
133 - public void processIcmpPacket(PacketContext context, Ethernet ethernet) {
134 - checkNotNull(context, "context can not be null");
135 - checkNotNull(ethernet, "ethernet can not be null");
136 -
137 IPv4 ipPacket = (IPv4) ethernet.getPayload(); 137 IPv4 ipPacket = (IPv4) ethernet.getPayload();
138 - 138 + log.trace("Processing ICMP packet from ip {}, mac {}",
139 - log.debug("icmpEvent called from ip {}, mac {}", Ip4Address.valueOf(ipPacket.getSourceAddress()).toString(), 139 + Ip4Address.valueOf(ipPacket.getSourceAddress()),
140 - ethernet.getSourceMAC().toString()); 140 + ethernet.getSourceMAC());
141 141
142 ICMP icmp = (ICMP) ipPacket.getPayload(); 142 ICMP icmp = (ICMP) ipPacket.getPayload();
143 short icmpId = getIcmpId(icmp); 143 short icmpId = getIcmpId(icmp);
144 144
145 - DeviceId deviceId = context.inPacket().receivedFrom().deviceId(); 145 + DeviceId srcDevice = context.inPacket().receivedFrom().deviceId();
146 - PortNumber portNumber = context.inPacket().receivedFrom().port(); 146 + switch (icmp.getIcmpType()) {
147 - if (icmp.getIcmpType() == ICMP.TYPE_ECHO_REQUEST) { 147 + case ICMP.TYPE_ECHO_REQUEST:
148 - //TODO: Considers icmp between internal subnets which are belonged to the same router. 148 + Optional<Host> reqHost = hostService.getHostsByMac(ethernet.getSourceMAC())
149 - Optional<Host> host = hostService.getHostsByMac(ethernet.getSourceMAC()).stream().findFirst(); 149 + .stream().findFirst();
150 - if (!host.isPresent()) { 150 + if (!reqHost.isPresent()) {
151 - log.warn("No host found for MAC {}", ethernet.getSourceMAC()); 151 + log.warn("No host found for MAC {}", ethernet.getSourceMAC());
152 - return; 152 + return;
153 - } 153 + }
154 - 154 +
155 - IpAddress gatewayIp = IpAddress.valueOf(host.get().annotations().value(Constants.GATEWAY_IP)); 155 + // TODO Considers icmp between internal subnets belong to the same router.
156 - if (ipPacket.getDestinationAddress() == gatewayIp.getIp4Address().toInt()) { 156 + // TODO do we have to support ICMP reply for non-existing gateway?
157 - processIcmpPacketSentToGateway(ipPacket, icmp, host.get()); 157 + Ip4Address gatewayIp = Ip4Address.valueOf(
158 - } else { 158 + reqHost.get().annotations().value(Constants.GATEWAY_IP));
159 - Ip4Address pNatIpAddress = pNatIpForPort(host.get()); 159 + if (Objects.equals(ipPacket.getDestinationAddress(), gatewayIp.toInt())) {
160 - checkNotNull(pNatIpAddress, "pNatIpAddress can not be null"); 160 + processRequestToGateway(ipPacket, reqHost.get());
161 - 161 + } else {
162 - sendRequestPacketToExt(ipPacket, icmp, deviceId, pNatIpAddress); 162 + Optional<Ip4Address> srcNatIp = getSrcNatIp(reqHost.get());
163 - 163 + if (!srcNatIp.isPresent()) {
164 + log.trace("VM {} has no external connection", reqHost.get());
165 + return;
166 + }
167 +
168 + sendRequestToExternal(ipPacket, srcDevice, srcNatIp.get());
169 + String icmpInfoKey = String.valueOf(icmpId)
170 + .concat(String.valueOf(srcNatIp.get().toInt()))
171 + .concat(String.valueOf(ipPacket.getDestinationAddress()));
172 + icmpInfoMap.putIfAbsent(icmpInfoKey, reqHost.get());
173 + }
174 + break;
175 + case ICMP.TYPE_ECHO_REPLY:
164 String icmpInfoKey = String.valueOf(icmpId) 176 String icmpInfoKey = String.valueOf(icmpId)
165 - .concat(String.valueOf(pNatIpAddress.toInt())) 177 + .concat(String.valueOf(ipPacket.getDestinationAddress()))
166 - .concat(String.valueOf(ipPacket.getDestinationAddress())); 178 + .concat(String.valueOf(ipPacket.getSourceAddress()));
167 - icmpInfoMap.putIfAbsent(icmpInfoKey, host.get()); 179 +
168 - } 180 + processReplyFromExternal(ipPacket, icmpInfoMap.get(icmpInfoKey));
169 - } else if (icmp.getIcmpType() == ICMP.TYPE_ECHO_REPLY) { 181 + icmpInfoMap.remove(icmpInfoKey);
170 - String icmpInfoKey = String.valueOf(icmpId) 182 + break;
171 - .concat(String.valueOf(ipPacket.getDestinationAddress())) 183 + default:
172 - .concat(String.valueOf(ipPacket.getSourceAddress())); 184 + break;
173 -
174 - processResponsePacketFromExternalToHost(ipPacket, icmp, icmpInfoMap.get(icmpInfoKey));
175 -
176 - icmpInfoMap.remove(icmpInfoKey);
177 } 185 }
178 } 186 }
179 187
180 - private void processIcmpPacketSentToExtenal(IPv4 icmpRequestIpv4, ICMP icmpRequest, 188 + // TODO do we have to handle the request to the fake gateway?
181 - int destAddr, MacAddress destMac, 189 + private void processRequestToGateway(IPv4 ipPacket, Host reqHost) {
182 - DeviceId deviceId, PortNumber portNumber) { 190 + ICMP icmpReq = (ICMP) ipPacket.getPayload();
183 - icmpRequest.setChecksum((short) 0); 191 + icmpReq.setChecksum((short) 0);
184 - icmpRequest.setIcmpType(ICMP.TYPE_ECHO_REPLY).resetChecksum(); 192 + icmpReq.setIcmpType(ICMP.TYPE_ECHO_REPLY).resetChecksum();
185 - icmpRequestIpv4.setSourceAddress(icmpRequestIpv4.getDestinationAddress())
186 - .setDestinationAddress(destAddr).resetChecksum();
187 - icmpRequestIpv4.setPayload(icmpRequest);
188 - Ethernet icmpResponseEth = new Ethernet();
189 - icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
190 - // TODO: Get the correct GW MAC
191 - .setSourceMACAddress(Constants.GW_EXT_INT_MAC)
192 - .setDestinationMACAddress(destMac).setPayload(icmpRequestIpv4);
193 - TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(portNumber).build();
194 - OutboundPacket packet = new DefaultOutboundPacket(deviceId,
195 - treatment, ByteBuffer.wrap(icmpResponseEth.serialize()));
196 - packetService.emit(packet);
197 - }
198 -
199 - private void processIcmpPacketSentToGateway(IPv4 icmpRequestIpv4, ICMP icmpRequest,
200 - Host host) {
201 - icmpRequest.setChecksum((short) 0);
202 - icmpRequest.setIcmpType(ICMP.TYPE_ECHO_REPLY)
203 - .resetChecksum();
204 193
205 - Ip4Address ipAddress = host.ipAddresses().stream().findAny().get().getIp4Address(); 194 + ipPacket.setSourceAddress(ipPacket.getDestinationAddress())
206 - icmpRequestIpv4.setSourceAddress(icmpRequestIpv4.getDestinationAddress()) 195 + .setDestinationAddress(ipPacket.getSourceAddress())
207 - .setDestinationAddress(ipAddress.toInt())
208 .resetChecksum(); 196 .resetChecksum();
209 197
210 - icmpRequestIpv4.setPayload(icmpRequest); 198 + ipPacket.setPayload(icmpReq);
199 + Ethernet icmpReply = new Ethernet();
200 + icmpReply.setEtherType(Ethernet.TYPE_IPV4)
201 + .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
202 + .setDestinationMACAddress(reqHost.mac())
203 + .setPayload(icmpReq);
211 204
212 - Ethernet icmpResponseEth = new Ethernet(); 205 + sendReply(icmpReply, reqHost);
213 -
214 - icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
215 - .setSourceMACAddress(Constants.GATEWAY_MAC)
216 - .setDestinationMACAddress(host.mac())
217 - .setPayload(icmpRequestIpv4);
218 -
219 - sendResponsePacketToHost(icmpResponseEth, host);
220 } 206 }
221 207
222 - private void sendRequestPacketToExt(IPv4 icmpRequestIpv4, ICMP icmpRequest, DeviceId deviceId, 208 + private void sendRequestToExternal(IPv4 ipPacket, DeviceId srcDevice, Ip4Address srcNatIp) {
223 - Ip4Address pNatIpAddress) { 209 + ICMP icmpReq = (ICMP) ipPacket.getPayload();
224 - icmpRequest.resetChecksum(); 210 + icmpReq.resetChecksum();
225 - icmpRequestIpv4.setSourceAddress(pNatIpAddress.toInt()) 211 + ipPacket.setSourceAddress(srcNatIp.toInt()).resetChecksum();
226 - .resetChecksum(); 212 + ipPacket.setPayload(icmpReq);
227 - icmpRequestIpv4.setPayload(icmpRequest);
228 213
229 Ethernet icmpRequestEth = new Ethernet(); 214 Ethernet icmpRequestEth = new Ethernet();
230 -
231 icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4) 215 icmpRequestEth.setEtherType(Ethernet.TYPE_IPV4)
232 - // TODO: Get the correct one - Scalable Gateway ... 216 + .setSourceMACAddress(DEFAULT_GATEWAY_MAC)
233 - .setSourceMACAddress(Constants.GW_EXT_INT_MAC) 217 + .setDestinationMACAddress(DEFAULT_EXTERNAL_ROUTER_MAC)
234 - .setDestinationMACAddress(Constants.PHY_ROUTER_MAC) 218 + .setPayload(ipPacket);
235 - .setPayload(icmpRequestIpv4);
236 -
237 - // TODO: Return the correct gateway node
238 - Optional<OpenstackNode> gwNode = nodeService.nodes().stream()
239 - .filter(n -> n.type().equals(OpenstackNodeService.NodeType.GATEWAY))
240 - .findFirst();
241 -
242 - if (!gwNode.isPresent()) {
243 - log.warn("No Gateway is defined.");
244 - return;
245 - }
246 219
247 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 220 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
248 - // FIXME: please double check this. 221 + .setOutput(gatewayService.getUplinkPort(srcDevice))
249 - .setOutput(getPortForAnnotationPortName(gwNode.get().intBridge(),
250 - // FIXME: please double check this.
251 - org.onosproject.openstacknode.Constants.PATCH_INTG_BRIDGE))
252 .build(); 222 .build();
253 223
254 - OutboundPacket packet = new DefaultOutboundPacket(deviceId, 224 + OutboundPacket packet = new DefaultOutboundPacket(
255 - treatment, ByteBuffer.wrap(icmpRequestEth.serialize())); 225 + srcDevice,
226 + treatment,
227 + ByteBuffer.wrap(icmpRequestEth.serialize()));
256 228
257 packetService.emit(packet); 229 packetService.emit(packet);
258 } 230 }
259 231
260 - private void processResponsePacketFromExternalToHost(IPv4 icmpResponseIpv4, ICMP icmpResponse, 232 + private void processReplyFromExternal(IPv4 ipPacket, Host dstHost) {
261 - Host host) { 233 + ICMP icmpReply = (ICMP) ipPacket.getPayload();
262 - icmpResponse.resetChecksum(); 234 + icmpReply.resetChecksum();
263 235
264 - Ip4Address ipAddress = host.ipAddresses().stream().findFirst().get().getIp4Address(); 236 + Ip4Address ipAddress = dstHost.ipAddresses().stream().findFirst().get().getIp4Address();
265 - icmpResponseIpv4.setDestinationAddress(ipAddress.toInt()) 237 + ipPacket.setDestinationAddress(ipAddress.toInt())
266 .resetChecksum(); 238 .resetChecksum();
267 - icmpResponseIpv4.setPayload(icmpResponse); 239 + ipPacket.setPayload(icmpReply);
268 240
269 Ethernet icmpResponseEth = new Ethernet(); 241 Ethernet icmpResponseEth = new Ethernet();
270 -
271 icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4) 242 icmpResponseEth.setEtherType(Ethernet.TYPE_IPV4)
272 - .setSourceMACAddress(Constants.GATEWAY_MAC) 243 + .setSourceMACAddress(Constants.DEFAULT_GATEWAY_MAC)
273 - .setDestinationMACAddress(host.mac()) 244 + .setDestinationMACAddress(dstHost.mac())
274 - .setPayload(icmpResponseIpv4); 245 + .setPayload(ipPacket);
275 246
276 - sendResponsePacketToHost(icmpResponseEth, host); 247 + sendReply(icmpResponseEth, dstHost);
277 } 248 }
278 249
279 - private void sendResponsePacketToHost(Ethernet icmpResponseEth, Host host) { 250 + private void sendReply(Ethernet icmpReply, Host dstHost) {
280 -
281 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 251 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
282 - .setOutput(host.location().port()) 252 + .setOutput(dstHost.location().port())
283 .build(); 253 .build();
284 254
285 - OutboundPacket packet = new DefaultOutboundPacket(host.location().deviceId(), 255 + OutboundPacket packet = new DefaultOutboundPacket(
286 - treatment, ByteBuffer.wrap(icmpResponseEth.serialize())); 256 + dstHost.location().deviceId(),
257 + treatment,
258 + ByteBuffer.wrap(icmpReply.serialize()));
287 259
288 packetService.emit(packet); 260 packetService.emit(packet);
289 } 261 }
290 262
291 - private short getIcmpId(ICMP icmp) { 263 + private Optional<Ip4Address> getSrcNatIp(Host host) {
292 - return ByteBuffer.wrap(icmp.serialize(), 4, 2).getShort(); 264 + // TODO cache external gateway IP for each network because
293 - } 265 + // asking Neutron for every ICMP request is a bad idea
294 - 266 + Optional<OpenstackPort> osPort = openstackService.ports().stream()
295 - private Ip4Address pNatIpForPort(Host host) { 267 + .filter(port -> port.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
268 + Objects.equals(host.annotations().value(NETWORK_ID),
269 + port.networkId()))
270 + .findAny();
271 + if (!osPort.isPresent()) {
272 + return Optional.empty();
273 + }
296 274
297 - OpenstackPort openstackPort = openstackService.ports().stream() 275 + OpenstackRouter osRouter = openstackService.router(osPort.get().deviceId());
298 - .filter(p -> p.deviceOwner().equals(NETWORK_ROUTER_INTERFACE) && 276 + if (osRouter == null) {
299 - p.networkId().equals(host.annotations().value(Constants.NETWORK_ID))) 277 + return Optional.empty();
300 - .findAny().orElse(null); 278 + }
301 279
302 - checkNotNull(openstackPort, "openstackPort can not be null"); 280 + return osRouter.gatewayExternalInfo().externalFixedIps()
281 + .values().stream().findAny();
282 + }
303 283
304 - return openstackService.router(openstackPort.deviceId()) 284 + private short getIcmpId(ICMP icmp) {
305 - .gatewayExternalInfo().externalFixedIps().values() 285 + return ByteBuffer.wrap(icmp.serialize(), 4, 2).getShort();
306 - .stream().findAny().orElse(null);
307 } 286 }
308 287
309 - private PortNumber getPortForAnnotationPortName(DeviceId deviceId, String match) { 288 + private class InternalPacketProcessor implements PacketProcessor {
310 - Port port = deviceService.getPorts(deviceId).stream() 289 +
311 - .filter(p -> p.annotations().value(PORTNAME).equals(match)) 290 + @Override
312 - .findAny().orElse(null); 291 + public void process(PacketContext context) {
292 + if (context.isHandled()) {
293 + return;
294 + } else if (!gatewayService.getGatewayDeviceIds().contains(
295 + context.inPacket().receivedFrom().deviceId())) {
296 + // return if the packet is not from gateway nodes
297 + return;
298 + }
313 299
314 - checkNotNull(port, "port cannot be null"); 300 + InboundPacket pkt = context.inPacket();
301 + Ethernet ethernet = pkt.parsed();
302 + if (ethernet == null || ethernet.getEtherType() == Ethernet.TYPE_ARP) {
303 + return;
304 + }
315 305
316 - return port.number(); 306 + IPv4 iPacket = (IPv4) ethernet.getPayload();
307 + if (iPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
308 + eventExecutor.execute(() -> processIcmpPacket(context, ethernet));
309 + }
310 + }
317 } 311 }
318 312
319 - private boolean requestToOpenstackRoutingNetwork(int destAddr) { 313 + private class InternalNodeListener implements OpenstackNodeListener {
320 - OpenstackPort port = openstackService.ports().stream() 314 +
321 - .filter(p -> p.deviceOwner().equals(NETWORK_ROUTER_GATEWAY) || 315 + @Override
322 - p.deviceOwner().equals(NETWORK_FLOATING_IP)) 316 + public void event(OpenstackNodeEvent event) {
323 - .filter(p -> p.fixedIps().containsValue( 317 + OpenstackNode node = event.node();
324 - Ip4Address.valueOf(destAddr))) 318 +
325 - .findAny().orElse(null); 319 + switch (event.type()) {
326 - if (port == null) { 320 + case COMPLETE:
327 - return false; 321 + if (node.type() == GATEWAY) {
322 + log.info("GATEWAY node {} detected", node.hostname());
323 + eventExecutor.execute(() -> requestPacket(appId));
324 + }
325 + break;
326 + case INIT:
327 + case DEVICE_CREATED:
328 + case INCOMPLETE:
329 + default:
330 + break;
331 + }
328 } 332 }
329 - return true;
330 - }
331 - private Map<DeviceId, PortNumber> getExternalInfo() {
332 - Map<DeviceId, PortNumber> externalInfoMap = Maps.newHashMap();
333 - gatewayService.getGatewayDeviceIds().forEach(deviceId ->
334 - externalInfoMap.putIfAbsent(deviceId, gatewayService.getUplinkPort(deviceId)));
335 - return externalInfoMap;
336 } 333 }
337 } 334 }
......
...@@ -15,109 +15,156 @@ ...@@ -15,109 +15,156 @@
15 */ 15 */
16 package org.onosproject.openstacknetworking.routing; 16 package org.onosproject.openstacknetworking.routing;
17 17
18 +import org.apache.felix.scr.annotations.Activate;
19 +import org.apache.felix.scr.annotations.Component;
20 +import org.apache.felix.scr.annotations.Deactivate;
21 +import org.apache.felix.scr.annotations.Reference;
22 +import org.apache.felix.scr.annotations.ReferenceCardinality;
18 import org.onlab.packet.Ethernet; 23 import org.onlab.packet.Ethernet;
19 import org.onlab.packet.IPv4; 24 import org.onlab.packet.IPv4;
20 import org.onlab.packet.Ip4Address; 25 import org.onlab.packet.Ip4Address;
26 +import org.onlab.packet.IpAddress;
27 +import org.onlab.packet.IpPrefix;
21 import org.onlab.packet.MacAddress; 28 import org.onlab.packet.MacAddress;
22 import org.onlab.packet.TCP; 29 import org.onlab.packet.TCP;
30 +import org.onlab.packet.TpPort;
23 import org.onlab.packet.UDP; 31 import org.onlab.packet.UDP;
32 +import org.onlab.util.KryoNamespace;
33 +import org.onlab.util.Tools;
34 +import org.onosproject.core.ApplicationId;
35 +import org.onosproject.core.CoreService;
24 import org.onosproject.net.DeviceId; 36 import org.onosproject.net.DeviceId;
25 -import org.onosproject.net.Port; 37 +import org.onosproject.net.Host;
38 +import org.onosproject.net.device.DeviceService;
39 +import org.onosproject.net.flow.DefaultTrafficSelector;
26 import org.onosproject.net.flow.DefaultTrafficTreatment; 40 import org.onosproject.net.flow.DefaultTrafficTreatment;
41 +import org.onosproject.net.flow.TrafficSelector;
27 import org.onosproject.net.flow.TrafficTreatment; 42 import org.onosproject.net.flow.TrafficTreatment;
43 +import org.onosproject.net.flowobjective.DefaultForwardingObjective;
44 +import org.onosproject.net.flowobjective.FlowObjectiveService;
45 +import org.onosproject.net.flowobjective.ForwardingObjective;
46 +import org.onosproject.net.host.HostService;
28 import org.onosproject.net.packet.DefaultOutboundPacket; 47 import org.onosproject.net.packet.DefaultOutboundPacket;
29 import org.onosproject.net.packet.InboundPacket; 48 import org.onosproject.net.packet.InboundPacket;
30 import org.onosproject.net.packet.PacketContext; 49 import org.onosproject.net.packet.PacketContext;
50 +import org.onosproject.net.packet.PacketProcessor;
31 import org.onosproject.net.packet.PacketService; 51 import org.onosproject.net.packet.PacketService;
32 import org.onosproject.openstackinterface.OpenstackInterfaceService; 52 import org.onosproject.openstackinterface.OpenstackInterfaceService;
33 import org.onosproject.openstackinterface.OpenstackPort; 53 import org.onosproject.openstackinterface.OpenstackPort;
34 import org.onosproject.openstackinterface.OpenstackRouter; 54 import org.onosproject.openstackinterface.OpenstackRouter;
35 -import org.onosproject.scalablegateway.api.GatewayNode; 55 +import org.onosproject.openstacknetworking.RulePopulatorUtil;
56 +import org.onosproject.openstacknode.OpenstackNodeService;
36 import org.onosproject.scalablegateway.api.ScalableGatewayService; 57 import org.onosproject.scalablegateway.api.ScalableGatewayService;
58 +import org.onosproject.store.serializers.KryoNamespaces;
59 +import org.onosproject.store.service.ConsistentMap;
60 +import org.onosproject.store.service.Serializer;
61 +import org.onosproject.store.service.StorageService;
37 import org.slf4j.Logger; 62 import org.slf4j.Logger;
38 -import org.slf4j.LoggerFactory;
39 63
40 import java.nio.ByteBuffer; 64 import java.nio.ByteBuffer;
65 +import java.util.Objects;
66 +import java.util.Optional;
67 +import java.util.concurrent.ExecutorService;
41 68
42 -import static com.google.common.base.Preconditions.checkNotNull; 69 +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
43 -import static org.onlab.osgi.DefaultServiceDirectory.getService; 70 +import static org.onlab.util.Tools.groupedThreads;
44 - 71 +import static org.onosproject.openstacknetworking.Constants.*;
72 +import static org.slf4j.LoggerFactory.getLogger;
45 73
46 /** 74 /**
47 - * Handle NAT packet processing for Managing Flow Rules In Openstack Nodes. 75 + * Handle NAT packet processing for managing flow rules in openstack nodes.
48 */ 76 */
49 -public class OpenstackPnatHandler implements Runnable { 77 +@Component(immediate = true)
50 - 78 +public class OpenstackPnatHandler {
51 - volatile PacketContext context; 79 + private final Logger log = getLogger(getClass());
52 - private final Logger log = LoggerFactory.getLogger(getClass());
53 -
54 - private final OpenstackRoutingRulePopulator rulePopulator;
55 - private final int portNum;
56 - private final OpenstackPort openstackPort;
57 - private final Port port;
58 -
59 - private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
60 - private static final String EXTERNAL_PORT_NULL = "There is no external port in this deviceId []";
61 -
62 - OpenstackPnatHandler(OpenstackRoutingRulePopulator rulePopulator, PacketContext context,
63 - int portNum, OpenstackPort openstackPort, Port port) {
64 - this.rulePopulator = checkNotNull(rulePopulator);
65 - this.context = checkNotNull(context);
66 - this.portNum = checkNotNull(portNum);
67 - this.openstackPort = checkNotNull(openstackPort);
68 - this.port = checkNotNull(port);
69 - }
70 80
71 - @Override 81 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 - public void run() { 82 + protected CoreService coreService;
73 - InboundPacket inboundPacket = context.inPacket();
74 - Ethernet ethernet = checkNotNull(inboundPacket.parsed());
75 83
76 - //TODO: Considers IPV6 84 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
77 - if (ethernet.getEtherType() != Ethernet.TYPE_IPV4) { 85 + protected PacketService packetService;
78 - log.warn("Now, we just consider IP version 4");
79 - return;
80 - }
81 86
82 - OpenstackRouter router = getOpenstackRouter(openstackPort); 87 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 + protected HostService hostService;
83 89
84 - MacAddress externalMac = MacAddress.NONE; 90 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 - MacAddress routerMac = MacAddress.NONE; 91 + protected StorageService storageService;
86 92
87 - rulePopulator.populatePnatFlowRules(inboundPacket, openstackPort, portNum, 93 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 - getExternalIp(router), externalMac, routerMac); 94 + protected FlowObjectiveService flowObjectiveService;
89 95
90 - packetOut((Ethernet) ethernet.clone(), inboundPacket.receivedFrom().deviceId(), portNum, router); 96 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 - } 97 + protected DeviceService deviceService;
92 98
93 - private OpenstackRouter getOpenstackRouter(OpenstackPort openstackPort) { 99 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 - OpenstackInterfaceService networkingService = getService(OpenstackInterfaceService.class); 100 + protected OpenstackInterfaceService openstackService;
95 101
96 - OpenstackPort port = networkingService.ports() 102 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
97 - .stream() 103 + protected OpenstackNodeService nodeService;
98 - .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
99 - .filter(p -> checkSameSubnet(p, openstackPort))
100 - .findAny()
101 - .orElse(null);
102 104
103 - return checkNotNull(networkingService.router(port.deviceId())); 105 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 - } 106 + protected ScalableGatewayService gatewayService;
105 107
106 - private boolean checkSameSubnet(OpenstackPort p, OpenstackPort openstackPort) { 108 + private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
107 - String key1 = checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString(); 109 + .register(KryoNamespaces.API);
108 - String key2 = checkNotNull(openstackPort.fixedIps().keySet().stream().findFirst().orElse(null)).toString(); 110 +
109 - return key1.equals(key2) ? true : false; 111 + private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
110 - } 112 + private static final int TP_PORT_MINIMUM_NUM = 1024;
113 + private static final int TP_PORT_MAXIMUM_NUM = 65535;
114 +
115 + private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
116 + groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
117 + private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
118 +
119 + private ConsistentMap<Integer, String> tpPortNumMap;
120 + private ApplicationId appId;
121 +
122 + @Activate
123 + protected void activate() {
124 + appId = coreService.registerApplication(ROUTING_APP_ID);
125 + tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
126 + .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
127 + .withName("openstackrouting-tpportnum")
128 + .withApplicationId(appId)
129 + .build();
111 130
112 - private Ip4Address getExternalIp(OpenstackRouter router) { 131 + packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
113 - return router.gatewayExternalInfo().externalFixedIps().values().stream().findAny().orElse(null); 132 + log.info("Started");
114 } 133 }
115 134
116 - private void packetOut(Ethernet ethernet, DeviceId deviceId, int portNum, OpenstackRouter router) { 135 + @Deactivate
117 - PacketService packetService = getService(PacketService.class); 136 + protected void deactivate() {
137 + packetService.removeProcessor(packetProcessor);
138 + log.info("Stopped");
139 + }
118 140
141 + private void processPnatPacket(PacketContext context, Ethernet ethernet) {
119 IPv4 iPacket = (IPv4) ethernet.getPayload(); 142 IPv4 iPacket = (IPv4) ethernet.getPayload();
143 + InboundPacket inboundPacket = context.inPacket();
144 +
145 + int srcPort = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
146 + OpenstackPort osPort = getOpenstackPort(ethernet.getSourceMAC());
147 + if (osPort == null) {
148 + return;
149 + }
150 + Ip4Address externalGatewayIp = getExternalGatewayIp(osPort);
151 + if (externalGatewayIp == null) {
152 + return;
153 + }
154 +
155 + populatePnatFlowRules(context.inPacket(),
156 + osPort,
157 + TpPort.tpPort(srcPort),
158 + externalGatewayIp);
159 +
160 + packetOut((Ethernet) ethernet.clone(),
161 + inboundPacket.receivedFrom().deviceId(),
162 + srcPort,
163 + externalGatewayIp);
164 + }
120 165
166 + private void packetOut(Ethernet ethernet, DeviceId deviceId, int portNum, Ip4Address externalIp) {
167 + IPv4 iPacket = (IPv4) ethernet.getPayload();
121 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder(); 168 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
122 169
123 switch (iPacket.getProtocol()) { 170 switch (iPacket.getProtocol()) {
...@@ -136,26 +183,251 @@ public class OpenstackPnatHandler implements Runnable { ...@@ -136,26 +183,251 @@ public class OpenstackPnatHandler implements Runnable {
136 iPacket.setPayload(udpPacket); 183 iPacket.setPayload(udpPacket);
137 break; 184 break;
138 default: 185 default:
139 - log.error("Temporally, this method can process UDP and TCP protocol."); 186 + log.trace("Temporally, this method can process UDP and TCP protocol.");
140 return; 187 return;
141 } 188 }
142 189
143 - iPacket.setSourceAddress(getExternalIp(router).toString()); 190 + iPacket.setSourceAddress(externalIp.toString());
144 iPacket.resetChecksum(); 191 iPacket.resetChecksum();
145 iPacket.setParent(ethernet); 192 iPacket.setParent(ethernet);
146 ethernet.setPayload(iPacket); 193 ethernet.setPayload(iPacket);
147 194
148 - ScalableGatewayService gatewayService = getService(ScalableGatewayService.class); 195 + treatment.setOutput(gatewayService.getUplinkPort(deviceId));
149 - GatewayNode gatewayNode = gatewayService.getGatewayNode(deviceId); 196 + ethernet.resetChecksum();
150 - if (gatewayNode.getUplinkIntf() == null) { 197 + packetService.emit(new DefaultOutboundPacket(
151 - log.error(EXTERNAL_PORT_NULL, deviceId.toString()); 198 + deviceId,
199 + treatment.build(),
200 + ByteBuffer.wrap(ethernet.serialize())));
201 + }
202 +
203 + private int getPortNum(MacAddress sourceMac, int destinationAddress) {
204 + int portNum = findUnusedPortNum();
205 + if (portNum == 0) {
206 + clearPortNumMap();
207 + portNum = findUnusedPortNum();
208 + }
209 + tpPortNumMap.put(portNum, sourceMac.toString().concat(":").concat(String.valueOf(destinationAddress)));
210 + return portNum;
211 + }
212 +
213 + private int findUnusedPortNum() {
214 + for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
215 + if (!tpPortNumMap.containsKey(i)) {
216 + return i;
217 + }
218 + }
219 + return 0;
220 + }
221 +
222 + private void clearPortNumMap() {
223 + tpPortNumMap.entrySet().forEach(e -> {
224 + if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
225 + tpPortNumMap.remove(e.getKey());
226 + }
227 + });
228 + }
229 +
230 + // TODO there can be multiple routers connected to a particular openstack port
231 + // TODO cache router information
232 + private Ip4Address getExternalGatewayIp(OpenstackPort osPort) {
233 + Optional<OpenstackPort> routerPort = openstackService.ports().stream()
234 + .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
235 + .filter(p -> checkSameSubnet(p, osPort))
236 + .findAny();
237 + if (!routerPort.isPresent()) {
238 + log.warn("No router is connected to network {}", osPort.networkId());
239 + return null;
240 + }
241 +
242 + OpenstackRouter osRouter = openstackService.router(routerPort.get().deviceId());
243 + if (osRouter == null) {
244 + log.warn("Failed to get OpenStack router {}",
245 + routerPort.get().deviceId());
246 + return null;
247 + }
248 +
249 + return osRouter.gatewayExternalInfo().externalFixedIps().values()
250 + .stream().findAny().orElse(null);
251 + }
252 +
253 + private OpenstackPort getOpenstackPort(MacAddress srcMac) {
254 + Optional<Host> host = hostService.getHostsByMac(srcMac).stream()
255 + .filter(h -> h.annotations().value(PORT_ID) != null)
256 + .findAny();
257 + if (!host.isPresent()) {
258 + log.warn("Failed to find a host with MAC:{}", srcMac);
259 + return null;
260 + }
261 + return openstackService.port(host.get().annotations().value(PORT_ID));
262 + }
263 +
264 + private boolean checkSameSubnet(OpenstackPort osPortA, OpenstackPort osPortB) {
265 + return osPortA.fixedIps().keySet().stream()
266 + .anyMatch(subnetId -> osPortB.fixedIps().keySet().contains(subnetId));
267 + }
268 +
269 + private void populatePnatFlowRules(InboundPacket inboundPacket,
270 + OpenstackPort osPort,
271 + TpPort patPort,
272 + Ip4Address externalIp) {
273 + long vni = getVni(osPort.networkId());
274 + populatePnatIncomingFlowRules(vni, externalIp, patPort, inboundPacket);
275 + populatePnatOutgoingFlowRules(vni, externalIp, patPort, inboundPacket);
276 + }
277 +
278 + private long getVni(String netId) {
279 + // TODO remove this and use host vxlan annotation if applicable
280 + return Long.parseLong(openstackService.network(netId).segmentId());
281 + }
282 +
283 + private void populatePnatOutgoingFlowRules(long vni, Ip4Address externalIp, TpPort patPort,
284 + InboundPacket inboundPacket) {
285 + IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
286 +
287 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
288 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
289 + .matchIPProtocol(iPacket.getProtocol())
290 + .matchTunnelId(vni)
291 + .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), 32))
292 + .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
293 +
294 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
295 + switch (iPacket.getProtocol()) {
296 + case IPv4.PROTOCOL_TCP:
297 + TCP tcpPacket = (TCP) iPacket.getPayload();
298 + sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
299 + .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
300 + tBuilder.setTcpSrc(patPort)
301 + .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC);
302 + break;
303 + case IPv4.PROTOCOL_UDP:
304 + UDP udpPacket = (UDP) iPacket.getPayload();
305 + sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
306 + .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
307 + tBuilder.setUdpSrc(patPort)
308 + .setEthDst(DEFAULT_EXTERNAL_ROUTER_MAC);
309 +
310 + break;
311 + default:
312 + log.debug("Unsupported IPv4 protocol {}");
313 + break;
314 + }
315 +
316 + tBuilder.setIpSrc(externalIp);
317 + gatewayService.getGatewayNodes().stream().forEach(gateway -> {
318 + TrafficTreatment.Builder tmpBuilder = tBuilder;
319 + tmpBuilder.setOutput(gatewayService.getUplinkPort(gateway.getGatewayDeviceId()));
320 + ForwardingObjective fo = DefaultForwardingObjective.builder()
321 + .withSelector(sBuilder.build())
322 + .withTreatment(tmpBuilder.build())
323 + .withFlag(ForwardingObjective.Flag.VERSATILE)
324 + .withPriority(PNAT_RULE_PRIORITY)
325 + .makeTemporary(PNAT_TIMEOUT)
326 + .fromApp(appId)
327 + .add();
328 +
329 + flowObjectiveService.forward(gateway.getGatewayDeviceId(), fo);
330 + });
331 + }
332 +
333 + private void populatePnatIncomingFlowRules(long vni, Ip4Address externalIp, TpPort patPort,
334 + InboundPacket inboundPacket) {
335 + IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
336 + IpAddress internalIp = IpAddress.valueOf(iPacket.getSourceAddress());
337 +
338 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
339 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
340 + .matchIPProtocol(iPacket.getProtocol())
341 + .matchIPDst(IpPrefix.valueOf(externalIp, 32))
342 + .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
343 +
344 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
345 + tBuilder.setTunnelId(vni)
346 + .setEthDst(inboundPacket.parsed().getSourceMAC())
347 + .setIpDst(internalIp);
348 +
349 + switch (iPacket.getProtocol()) {
350 + case IPv4.PROTOCOL_TCP:
351 + TCP tcpPacket = (TCP) iPacket.getPayload();
352 + sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
353 + .matchTcpDst(patPort);
354 + tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
355 + break;
356 + case IPv4.PROTOCOL_UDP:
357 + UDP udpPacket = (UDP) iPacket.getPayload();
358 + sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
359 + .matchUdpDst(patPort);
360 + tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
361 + break;
362 + default:
363 + break;
364 + }
365 +
366 + Optional<Host> srcVm = Tools.stream(hostService.getHostsByIp(internalIp))
367 + .filter(host -> Objects.equals(
368 + host.annotations().value(VXLAN_ID),
369 + String.valueOf(vni)))
370 + .findFirst();
371 + if (!srcVm.isPresent()) {
372 + log.warn("Failed to find source VM with IP {}", internalIp);
152 return; 373 return;
153 } 374 }
154 - treatment.setOutput(gatewayService.getUplinkPort(deviceId));
155 375
156 - ethernet.resetChecksum(); 376 + gatewayService.getGatewayDeviceIds().stream().forEach(deviceId -> {
377 + DeviceId srcDeviceId = srcVm.get().location().deviceId();
378 + TrafficTreatment.Builder tmpBuilder = tBuilder;
379 + tmpBuilder.extension(RulePopulatorUtil.buildExtension(
380 + deviceService,
381 + deviceId,
382 + nodeService.dataIp(srcDeviceId).get().getIp4Address()), deviceId)
383 + .setOutput(nodeService.tunnelPort(deviceId).get());
157 384
158 - packetService.emit(new DefaultOutboundPacket(deviceId, treatment.build(), 385 + ForwardingObjective fo = DefaultForwardingObjective.builder()
159 - ByteBuffer.wrap(ethernet.serialize()))); 386 + .withSelector(sBuilder.build())
387 + .withTreatment(tmpBuilder.build())
388 + .withFlag(ForwardingObjective.Flag.VERSATILE)
389 + .withPriority(PNAT_RULE_PRIORITY)
390 + .makeTemporary(PNAT_TIMEOUT)
391 + .fromApp(appId)
392 + .add();
393 +
394 + flowObjectiveService.forward(deviceId, fo);
395 + });
396 + }
397 +
398 + private class InternalPacketProcessor implements PacketProcessor {
399 +
400 + @Override
401 + public void process(PacketContext context) {
402 + if (context.isHandled()) {
403 + return;
404 + } else if (!gatewayService.getGatewayDeviceIds().contains(
405 + context.inPacket().receivedFrom().deviceId())) {
406 + // return if the packet is not from gateway nodes
407 + return;
408 + }
409 +
410 + InboundPacket pkt = context.inPacket();
411 + Ethernet ethernet = pkt.parsed();
412 + if (ethernet == null || ethernet.getEtherType() == Ethernet.TYPE_ARP) {
413 + return;
414 + }
415 +
416 + IPv4 iPacket = (IPv4) ethernet.getPayload();
417 + switch (iPacket.getProtocol()) {
418 + case IPv4.PROTOCOL_ICMP:
419 + break;
420 + case IPv4.PROTOCOL_UDP:
421 + UDP udpPacket = (UDP) iPacket.getPayload();
422 + if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
423 + udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
424 + // don't process DHCP
425 + break;
426 + }
427 + default:
428 + eventExecutor.execute(() -> processPnatPacket(context, ethernet));
429 + break;
430 + }
431 + }
160 } 432 }
161 } 433 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -15,99 +15,74 @@ ...@@ -15,99 +15,74 @@
15 */ 15 */
16 package org.onosproject.openstacknetworking.routing; 16 package org.onosproject.openstacknetworking.routing;
17 17
18 -import com.google.common.collect.Lists; 18 +import org.apache.felix.scr.annotations.Activate;
19 +import org.apache.felix.scr.annotations.Component;
20 +import org.apache.felix.scr.annotations.Deactivate;
21 +import org.apache.felix.scr.annotations.Reference;
22 +import org.apache.felix.scr.annotations.ReferenceCardinality;
19 import org.onlab.packet.ARP; 23 import org.onlab.packet.ARP;
20 -import org.onlab.packet.EthType;
21 import org.onlab.packet.Ethernet; 24 import org.onlab.packet.Ethernet;
22 import org.onlab.packet.Ip4Address; 25 import org.onlab.packet.Ip4Address;
23 import org.onlab.packet.IpAddress; 26 import org.onlab.packet.IpAddress;
24 import org.onlab.packet.MacAddress; 27 import org.onlab.packet.MacAddress;
25 -import org.onosproject.core.ApplicationId;
26 -import org.onosproject.net.DeviceId;
27 -import org.onosproject.net.flow.DefaultTrafficSelector;
28 import org.onosproject.net.flow.DefaultTrafficTreatment; 28 import org.onosproject.net.flow.DefaultTrafficTreatment;
29 -import org.onosproject.net.flow.TrafficSelector;
30 import org.onosproject.net.flow.TrafficTreatment; 29 import org.onosproject.net.flow.TrafficTreatment;
31 import org.onosproject.net.packet.DefaultOutboundPacket; 30 import org.onosproject.net.packet.DefaultOutboundPacket;
31 +import org.onosproject.net.packet.InboundPacket;
32 import org.onosproject.net.packet.PacketContext; 32 import org.onosproject.net.packet.PacketContext;
33 -import org.onosproject.net.packet.PacketPriority; 33 +import org.onosproject.net.packet.PacketProcessor;
34 import org.onosproject.net.packet.PacketService; 34 import org.onosproject.net.packet.PacketService;
35 import org.onosproject.openstackinterface.OpenstackInterfaceService; 35 import org.onosproject.openstackinterface.OpenstackInterfaceService;
36 import org.onosproject.openstackinterface.OpenstackPort; 36 import org.onosproject.openstackinterface.OpenstackPort;
37 import org.onosproject.scalablegateway.api.ScalableGatewayService; 37 import org.onosproject.scalablegateway.api.ScalableGatewayService;
38 import org.onosproject.openstacknetworking.Constants; 38 import org.onosproject.openstacknetworking.Constants;
39 -import org.onosproject.openstacknode.OpenstackNodeService;
40 import org.slf4j.Logger; 39 import org.slf4j.Logger;
41 40
42 import java.nio.ByteBuffer; 41 import java.nio.ByteBuffer;
43 -import java.util.List; 42 +import java.util.concurrent.ExecutorService;
44 -import java.util.Optional;
45 43
46 -import static com.google.common.base.Preconditions.checkNotNull; 44 +import static java.util.concurrent.Executors.newSingleThreadExecutor;
45 +import static org.onlab.util.Tools.groupedThreads;
46 +import static org.onosproject.openstacknetworking.Constants.DEVICE_OWNER_FLOATING_IP;
47 +import static org.onosproject.openstacknetworking.Constants.DEVICE_OWNER_ROUTER_GATEWAY;
47 import static org.slf4j.LoggerFactory.getLogger; 48 import static org.slf4j.LoggerFactory.getLogger;
48 49
49 /** 50 /**
50 - * Handle ARP packet sent from Openstack Gateway nodes. 51 + * Handle ARP, ICMP and NAT packets from gateway nodes.
51 */ 52 */
53 +@Component(immediate = true)
52 public class OpenstackRoutingArpHandler { 54 public class OpenstackRoutingArpHandler {
53 - protected final Logger log = getLogger(getClass()); 55 + private final Logger log = getLogger(getClass());
54 -
55 - private final PacketService packetService;
56 - private final OpenstackInterfaceService openstackService;
57 - private final ScalableGatewayService gatewayService;
58 - private final OpenstackNodeService nodeService;
59 - private static final String NETWORK_ROUTER_GATEWAY = "network:router_gateway";
60 - private static final String NETWORK_FLOATING_IP = "network:floatingip";
61 -
62 - /**
63 - * Default constructor.
64 - *
65 - * @param packetService packet service
66 - * @param openstackService openstackInterface service
67 - * @param gatewayService gateway service
68 - * @param nodeService openstackNodeService
69 - */
70 - OpenstackRoutingArpHandler(PacketService packetService, OpenstackInterfaceService openstackService,
71 - OpenstackNodeService nodeService, ScalableGatewayService gatewayService) {
72 - this.packetService = packetService;
73 - this.openstackService = checkNotNull(openstackService);
74 - this.nodeService = nodeService;
75 - this.gatewayService = gatewayService;
76 - }
77 56
78 - /** 57 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 - * Requests ARP packet to GatewayNode. 58 + protected PacketService packetService;
80 - *
81 - * @param appId application id
82 - */
83 - public void requestPacket(ApplicationId appId) {
84 59
85 - TrafficSelector arpSelector = DefaultTrafficSelector.builder() 60 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 - .matchEthType(EthType.EtherType.ARP.ethType().toShort()) 61 + protected OpenstackInterfaceService openstackService;
87 - .build();
88 62
89 - getExternalInfo().forEach(deviceId -> 63 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 - packetService.requestPackets(arpSelector, 64 + protected ScalableGatewayService gatewayService;
91 - PacketPriority.CONTROL,
92 - appId,
93 - Optional.of(deviceId))
94 - );
95 - }
96 65
97 - /** 66 + private final ExecutorService executorService =
98 - * Handles ARP packet. 67 + newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "packet-event", log));
99 - *
100 - * @param context packet context
101 - * @param ethernet ethernet
102 - */
103 - public void processArpPacketFromRouter(PacketContext context, Ethernet ethernet) {
104 - checkNotNull(context, "context can not be null");
105 - checkNotNull(ethernet, "ethernet can not be null");
106 68
69 + private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
107 70
108 - ARP arp = (ARP) ethernet.getPayload(); 71 + @Activate
72 + protected void activate() {
73 + packetService.addProcessor(packetProcessor, PacketProcessor.director(1));
74 + log.info("Started");
75 + }
109 76
110 - log.debug("arpEvent called from {} to {}", 77 + @Deactivate
78 + protected void deactivate() {
79 + packetService.removeProcessor(packetProcessor);
80 + log.info("Stopped");
81 + }
82 +
83 + private void processArpPacket(PacketContext context, Ethernet ethernet) {
84 + ARP arp = (ARP) ethernet.getPayload();
85 + log.trace("arpEvent called from {} to {}",
111 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(), 86 Ip4Address.valueOf(arp.getSenderProtocolAddress()).toString(),
112 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString()); 87 Ip4Address.valueOf(arp.getTargetProtocolAddress()).toString());
113 88
...@@ -116,13 +91,11 @@ public class OpenstackRoutingArpHandler { ...@@ -116,13 +91,11 @@ public class OpenstackRoutingArpHandler {
116 } 91 }
117 92
118 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress()); 93 IpAddress targetIp = Ip4Address.valueOf(arp.getTargetProtocolAddress());
119 -
120 if (getTargetMacForTargetIp(targetIp.getIp4Address()) == MacAddress.NONE) { 94 if (getTargetMacForTargetIp(targetIp.getIp4Address()) == MacAddress.NONE) {
121 - return; 95 + return;
122 } 96 }
123 - // FIXME: Set the correct gateway
124 - MacAddress targetMac = Constants.GW_EXT_INT_MAC;
125 97
98 + MacAddress targetMac = Constants.DEFAULT_EXTERNAL_ROUTER_MAC;
126 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(), 99 Ethernet ethReply = ARP.buildArpReply(targetIp.getIp4Address(),
127 targetMac, ethernet); 100 targetMac, ethernet);
128 101
...@@ -136,22 +109,35 @@ public class OpenstackRoutingArpHandler { ...@@ -136,22 +109,35 @@ public class OpenstackRoutingArpHandler {
136 ByteBuffer.wrap(ethReply.serialize()))); 109 ByteBuffer.wrap(ethReply.serialize())));
137 } 110 }
138 111
112 + private class InternalPacketProcessor implements PacketProcessor {
113 +
114 + @Override
115 + public void process(PacketContext context) {
116 + if (context.isHandled()) {
117 + return;
118 + } else if (!gatewayService.getGatewayDeviceIds().contains(
119 + context.inPacket().receivedFrom().deviceId())) {
120 + // return if the packet is not from gateway nodes
121 + return;
122 + }
123 +
124 + InboundPacket pkt = context.inPacket();
125 + Ethernet ethernet = pkt.parsed();
126 + if (ethernet != null &&
127 + ethernet.getEtherType() == Ethernet.TYPE_ARP) {
128 + executorService.execute(() -> processArpPacket(context, ethernet));
129 + }
130 + }
131 + }
132 +
133 + // TODO make a cache for the MAC, not a good idea to REST call every time it gets ARP request
139 private MacAddress getTargetMacForTargetIp(Ip4Address targetIp) { 134 private MacAddress getTargetMacForTargetIp(Ip4Address targetIp) {
140 OpenstackPort port = openstackService.ports().stream() 135 OpenstackPort port = openstackService.ports().stream()
141 - .filter(p -> p.deviceOwner().equals(NETWORK_ROUTER_GATEWAY) || 136 + .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_GATEWAY) ||
142 - p.deviceOwner().equals(NETWORK_FLOATING_IP)) 137 + p.deviceOwner().equals(DEVICE_OWNER_FLOATING_IP))
143 .filter(p -> p.fixedIps().containsValue(targetIp.getIp4Address())) 138 .filter(p -> p.fixedIps().containsValue(targetIp.getIp4Address()))
144 .findAny().orElse(null); 139 .findAny().orElse(null);
145 140
146 - if (port == null) { 141 + return port == null ? MacAddress.NONE : port.macAddress();
147 - return MacAddress.NONE;
148 - }
149 - return port.macAddress();
150 - }
151 -
152 - private List<DeviceId> getExternalInfo() {
153 - List<DeviceId> externalInfoList = Lists.newArrayList();
154 - gatewayService.getGatewayDeviceIds().forEach(externalInfoList::add);
155 - return externalInfoList;
156 } 142 }
157 } 143 }
......
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
15 */ 15 */
16 package org.onosproject.openstacknetworking.routing; 16 package org.onosproject.openstacknetworking.routing;
17 17
18 -import com.google.common.collect.Lists; 18 +import com.google.common.collect.ImmutableSet;
19 -import com.google.common.collect.Sets;
20 import org.apache.felix.scr.annotations.Activate; 19 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 20 import org.apache.felix.scr.annotations.Component;
22 import org.apache.felix.scr.annotations.Deactivate; 21 import org.apache.felix.scr.annotations.Deactivate;
...@@ -24,82 +23,62 @@ import org.apache.felix.scr.annotations.Reference; ...@@ -24,82 +23,62 @@ import org.apache.felix.scr.annotations.Reference;
24 import org.apache.felix.scr.annotations.ReferenceCardinality; 23 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 import org.apache.felix.scr.annotations.Service; 24 import org.apache.felix.scr.annotations.Service;
26 import org.onlab.packet.Ethernet; 25 import org.onlab.packet.Ethernet;
27 -import org.onlab.packet.IPv4;
28 import org.onlab.packet.Ip4Address; 26 import org.onlab.packet.Ip4Address;
29 -import org.onlab.packet.IpAddress;
30 import org.onlab.packet.MacAddress; 27 import org.onlab.packet.MacAddress;
31 -import org.onlab.packet.UDP; 28 +import org.onlab.util.Tools;
32 -import org.onlab.util.KryoNamespace;
33 import org.onosproject.core.ApplicationId; 29 import org.onosproject.core.ApplicationId;
34 -import org.onosproject.core.CoreService; 30 +import org.onosproject.core.GroupId;
35 -import org.onosproject.mastership.MastershipService;
36 -import org.onosproject.net.DefaultAnnotations;
37 import org.onosproject.net.DeviceId; 31 import org.onosproject.net.DeviceId;
38 import org.onosproject.net.Host; 32 import org.onosproject.net.Host;
39 -import org.onosproject.net.Port; 33 +import org.onosproject.net.PortNumber;
40 import org.onosproject.net.device.DeviceService; 34 import org.onosproject.net.device.DeviceService;
41 -import org.onosproject.net.driver.DriverService; 35 +import org.onosproject.net.flow.DefaultTrafficSelector;
36 +import org.onosproject.net.flow.DefaultTrafficTreatment;
37 +import org.onosproject.net.flow.TrafficSelector;
38 +import org.onosproject.net.flow.TrafficTreatment;
39 +import org.onosproject.net.flowobjective.DefaultForwardingObjective;
42 import org.onosproject.net.flowobjective.FlowObjectiveService; 40 import org.onosproject.net.flowobjective.FlowObjectiveService;
43 -import org.onosproject.net.host.DefaultHostDescription; 41 +import org.onosproject.net.flowobjective.ForwardingObjective;
44 -import org.onosproject.net.host.HostDescription;
45 -import org.onosproject.net.host.HostEvent;
46 -import org.onosproject.net.host.HostListener;
47 -import org.onosproject.net.host.HostProvider;
48 -import org.onosproject.net.host.HostProviderRegistry;
49 -import org.onosproject.net.host.HostProviderService;
50 -import org.onosproject.net.host.HostService;
51 -import org.onosproject.net.packet.InboundPacket;
52 -import org.onosproject.net.packet.PacketContext;
53 -import org.onosproject.net.packet.PacketProcessor;
54 -import org.onosproject.net.packet.PacketService;
55 -import org.onosproject.net.provider.AbstractProvider;
56 -import org.onosproject.net.provider.ProviderId;
57 -import org.onosproject.openstackinterface.OpenstackFloatingIP;
58 import org.onosproject.openstackinterface.OpenstackInterfaceService; 42 import org.onosproject.openstackinterface.OpenstackInterfaceService;
43 +import org.onosproject.openstackinterface.OpenstackNetwork;
59 import org.onosproject.openstackinterface.OpenstackPort; 44 import org.onosproject.openstackinterface.OpenstackPort;
60 import org.onosproject.openstackinterface.OpenstackRouter; 45 import org.onosproject.openstackinterface.OpenstackRouter;
61 import org.onosproject.openstackinterface.OpenstackRouterInterface; 46 import org.onosproject.openstackinterface.OpenstackRouterInterface;
62 -import org.onosproject.openstacknetworking.OpenstackRoutingService; 47 +import org.onosproject.openstackinterface.OpenstackSubnet;
63 -import org.onosproject.scalablegateway.api.ScalableGatewayService; 48 +import org.onosproject.openstacknetworking.AbstractVmHandler;
64 -import org.onosproject.openstacknetworking.routing.OpenstackFloatingIPHandler.Action;
65 import org.onosproject.openstacknetworking.Constants; 49 import org.onosproject.openstacknetworking.Constants;
50 +import org.onosproject.openstacknetworking.OpenstackRoutingService;
51 +import org.onosproject.openstacknetworking.RulePopulatorUtil;
66 import org.onosproject.openstacknode.OpenstackNode; 52 import org.onosproject.openstacknode.OpenstackNode;
67 import org.onosproject.openstacknode.OpenstackNodeEvent; 53 import org.onosproject.openstacknode.OpenstackNodeEvent;
68 import org.onosproject.openstacknode.OpenstackNodeListener; 54 import org.onosproject.openstacknode.OpenstackNodeListener;
69 import org.onosproject.openstacknode.OpenstackNodeService; 55 import org.onosproject.openstacknode.OpenstackNodeService;
70 -import org.onosproject.store.serializers.KryoNamespaces; 56 +import org.onosproject.scalablegateway.api.GatewayNode;
71 -import org.onosproject.store.service.ConsistentMap; 57 +import org.onosproject.scalablegateway.api.ScalableGatewayService;
72 -import org.onosproject.store.service.Serializer;
73 -import org.onosproject.store.service.StorageService;
74 import org.slf4j.Logger; 58 import org.slf4j.Logger;
75 import org.slf4j.LoggerFactory; 59 import org.slf4j.LoggerFactory;
76 60
77 -import java.util.Collection; 61 +import java.util.Objects;
78 -import java.util.List;
79 import java.util.Optional; 62 import java.util.Optional;
80 import java.util.Set; 63 import java.util.Set;
81 import java.util.concurrent.ExecutorService; 64 import java.util.concurrent.ExecutorService;
82 -import java.util.concurrent.Executors;
83 import java.util.stream.Collectors; 65 import java.util.stream.Collectors;
84 66
85 -import static com.google.common.base.Preconditions.checkNotNull; 67 +import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
86 import static org.onlab.util.Tools.groupedThreads; 68 import static org.onlab.util.Tools.groupedThreads;
87 -import static org.onosproject.net.AnnotationKeys.PORT_NAME; 69 +import static org.onosproject.openstacknetworking.Constants.*;
70 +import static org.onosproject.openstacknetworking.RulePopulatorUtil.buildExtension;
71 +import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.COMPUTE;
72 +import static org.onosproject.openstacknode.OpenstackNodeService.NodeType.GATEWAY;
88 73
89 @Component(immediate = true) 74 @Component(immediate = true)
90 @Service 75 @Service
91 -/** 76 +public class OpenstackRoutingManager extends AbstractVmHandler implements OpenstackRoutingService {
92 - * Populates flow rules about L3 functionality for VMs in Openstack.
93 - */
94 -public class OpenstackRoutingManager implements OpenstackRoutingService {
95 77
96 private final Logger log = LoggerFactory.getLogger(getClass()); 78 private final Logger log = LoggerFactory.getLogger(getClass());
97 79
98 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 80 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
99 - protected CoreService coreService; 81 + protected FlowObjectiveService flowObjectiveService;
100 -
101 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
102 - protected PacketService packetService;
103 82
104 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 83 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
105 protected DeviceService deviceService; 84 protected DeviceService deviceService;
...@@ -108,620 +87,392 @@ public class OpenstackRoutingManager implements OpenstackRoutingService { ...@@ -108,620 +87,392 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
108 protected OpenstackInterfaceService openstackService; 87 protected OpenstackInterfaceService openstackService;
109 88
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
111 - protected FlowObjectiveService flowObjectiveService; 90 + protected OpenstackNodeService nodeService;
112 -
113 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 - protected DriverService driverService;
115 -
116 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 - protected StorageService storageService;
118 -
119 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 - protected HostService hostService;
121 -
122 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 - protected HostProviderRegistry hostProviderRegistry;
124 91
125 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 92 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
126 protected ScalableGatewayService gatewayService; 93 protected ScalableGatewayService gatewayService;
127 94
128 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 95 + private final ExecutorService eventExecutor = newSingleThreadScheduledExecutor(
129 - protected OpenstackNodeService nodeService; 96 + groupedThreads(this.getClass().getSimpleName(), "event-handler", log));
130 - 97 + private final InternalNodeListener nodeListener = new InternalNodeListener();
131 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
132 - protected MastershipService mastershipService;
133 98
134 private ApplicationId appId; 99 private ApplicationId appId;
135 - private ConsistentMap<Integer, String> tpPortNumMap; // Map<PortNum, allocated VM`s Mac & destionation Ip address>
136 - private ConsistentMap<String, OpenstackFloatingIP> floatingIpMap; // Map<FloatingIp`s Id, FloatingIp object>
137 - // Map<RouterInterface`s portId, Corresponded port`s network id>
138 - private ConsistentMap<String, String> routerInterfaceMap;
139 - private static final ProviderId PID = new ProviderId("of", "org.onosproject.openstackroutering", true);
140 - private static final String APP_ID = "org.onosproject.openstackrouting";
141 - private static final String DEVICE_OWNER_ROUTER_INTERFACE = "network:router_interface";
142 - private static final String FLOATING_IP_MAP_NAME = "openstackrouting-floatingip";
143 - private static final String TP_PORT_MAP_NAME = "openstackrouting-tpportnum";
144 - private static final String ROUTER_INTERFACE_MAP_NAME = "openstackrouting-routerinterface";
145 - private static final String COLON = ":";
146 - private static final int PNAT_PORT_EXPIRE_TIME = 1200 * 1000;
147 - private static final int TP_PORT_MINIMUM_NUM = 1024;
148 - private static final int TP_PORT_MAXIMUM_NUM = 65535;
149 -
150 - private static final KryoNamespace.Builder FLOATING_IP_SERIALIZER = KryoNamespace.newBuilder()
151 - .register(KryoNamespaces.API)
152 - .register(OpenstackFloatingIP.FloatingIpStatus.class)
153 - .register(OpenstackFloatingIP.class);
154 -
155 - private static final KryoNamespace.Builder NUMBER_SERIALIZER = KryoNamespace.newBuilder()
156 - .register(KryoNamespaces.API);
157 -
158 - private static final KryoNamespace.Builder ROUTER_INTERFACE_SERIALIZER = KryoNamespace.newBuilder()
159 - .register(KryoNamespaces.API);
160 -
161 - private InternalPacketProcessor internalPacketProcessor = new InternalPacketProcessor();
162 - private InternalHostListener internalHostListener = new InternalHostListener();
163 - private InternalOpenstackNodeListener internalNodeListener = new InternalOpenstackNodeListener();
164 - private ExecutorService l3EventExecutorService =
165 - Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "L3-event"));
166 - private ExecutorService icmpEventExecutorService =
167 - Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "icmp-event"));
168 - private ExecutorService arpEventExecutorService =
169 - Executors.newSingleThreadExecutor(groupedThreads("onos/openstackrouting", "arp-event"));
170 - private OpenstackIcmpHandler openstackIcmpHandler;
171 - private OpenstackRoutingArpHandler openstackArpHandler;
172 - private OpenstackRoutingRulePopulator rulePopulator;
173 -
174 - private HostProviderService hostProviderService;
175 - private final HostProvider hostProvider = new InternalHostProvider();
176 100
177 @Activate 101 @Activate
178 protected void activate() { 102 protected void activate() {
179 - appId = coreService.registerApplication(APP_ID); 103 + super.activate();
180 - hostService.addListener(internalHostListener); 104 + appId = coreService.registerApplication(ROUTING_APP_ID);
181 - nodeService.addListener(internalNodeListener); 105 + nodeService.addListener(nodeListener);
182 - hostProviderService = hostProviderRegistry.register(hostProvider);
183 -
184 - floatingIpMap = storageService.<String, OpenstackFloatingIP>consistentMapBuilder()
185 - .withSerializer(Serializer.using(FLOATING_IP_SERIALIZER.build()))
186 - .withName(FLOATING_IP_MAP_NAME)
187 - .withApplicationId(appId)
188 - .build();
189 - tpPortNumMap = storageService.<Integer, String>consistentMapBuilder()
190 - .withSerializer(Serializer.using(NUMBER_SERIALIZER.build()))
191 - .withName(TP_PORT_MAP_NAME)
192 - .withApplicationId(appId)
193 - .build();
194 - routerInterfaceMap = storageService.<String, String>consistentMapBuilder()
195 - .withSerializer(Serializer.using(ROUTER_INTERFACE_SERIALIZER.build()))
196 - .withName(ROUTER_INTERFACE_MAP_NAME)
197 - .withApplicationId(appId)
198 - .build();
199 -
200 - log.info("started");
201 } 106 }
202 107
203 @Deactivate 108 @Deactivate
204 protected void deactivate() { 109 protected void deactivate() {
205 - packetService.removeProcessor(internalPacketProcessor); 110 + nodeService.removeListener(nodeListener);
206 - hostService.removeListener(internalHostListener);
207 - nodeService.removeListener(internalNodeListener);
208 -
209 - l3EventExecutorService.shutdown();
210 - icmpEventExecutorService.shutdown();
211 - arpEventExecutorService.shutdown();
212 -
213 - floatingIpMap.clear();
214 - tpPortNumMap.clear();
215 - routerInterfaceMap.clear();
216 -
217 log.info("stopped"); 111 log.info("stopped");
218 } 112 }
219 113
220 -
221 @Override 114 @Override
222 - public void createFloatingIP(OpenstackFloatingIP openstackFloatingIp) { 115 + public void createRouter(OpenstackRouter osRouter) {
223 - floatingIpMap.put(openstackFloatingIp.id(), openstackFloatingIp);
224 } 116 }
225 117
226 @Override 118 @Override
227 - public void updateFloatingIP(OpenstackFloatingIP openstackFloatingIp) { 119 + public void updateRouter(OpenstackRouter osRouter) {
228 - if (!floatingIpMap.containsKey(openstackFloatingIp.id())) { 120 + if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
229 - log.warn("There`s no information about {} in FloatingIpMap", openstackFloatingIp.id()); 121 + openstackService.ports().stream()
230 - return; 122 + .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
231 - } 123 + osPort.deviceId().equals(osRouter.id()))
232 - if (openstackFloatingIp.portId() == null || openstackFloatingIp.portId().equals("null")) { 124 + .forEach(osPort -> setExternalConnection(osRouter, osPort.networkId()));
233 - OpenstackFloatingIP floatingIp = floatingIpMap.get(openstackFloatingIp.id()).value(); 125 +
234 - // XXX When the VM has been removed, host information has been removed or not ??? 126 + log.info("Connected external gateway {} to router {}",
235 - Optional<Host> host = hostService.getHostsByIp(openstackFloatingIp.fixedIpAddress().getIp4Address()) 127 + osRouter.gatewayExternalInfo().externalFixedIps(),
236 - .stream() 128 + osRouter.name());
237 - .findFirst();
238 - if (!host.isPresent()) {
239 - log.warn("No Host info with the VM IP the Floating IP address {} is found",
240 - openstackFloatingIp.floatingIpAddress());
241 - return;
242 - }
243 - l3EventExecutorService.execute(
244 - new OpenstackFloatingIPHandler(rulePopulator, floatingIp, Action.DISSASSOCIATE, host.get()));
245 - floatingIpMap.replace(floatingIp.id(), openstackFloatingIp);
246 - registerFloatingIpToHostService(openstackFloatingIp, Action.DISSASSOCIATE);
247 } else { 129 } else {
248 - floatingIpMap.put(openstackFloatingIp.id(), openstackFloatingIp); 130 + openstackService.ports().stream()
249 - l3EventExecutorService.execute( 131 + .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
250 - new OpenstackFloatingIPHandler(rulePopulator, openstackFloatingIp, Action.ASSOCIATE, null)); 132 + osPort.deviceId().equals(osRouter.id()))
251 - registerFloatingIpToHostService(openstackFloatingIp, Action.ASSOCIATE); 133 + .forEach(osPort -> unsetExternalConnection(osRouter, osPort.networkId()));
252 - }
253 - }
254 134
255 - @Override 135 + log.info("Disconnected external gateway from router {}",
256 - public void deleteFloatingIP(String id) { 136 + osRouter.name());
257 - floatingIpMap.remove(id); 137 + }
258 } 138 }
259 139
260 @Override 140 @Override
261 - public void createRouter(OpenstackRouter openstackRouter) { 141 + public void removeRouter(String osRouterId) {
142 + // TODO implement this
262 } 143 }
263 144
264 @Override 145 @Override
265 - public void updateRouter(OpenstackRouter openstackRouter) { 146 + public void addRouterInterface(OpenstackRouterInterface routerIface) {
266 - if (openstackRouter.gatewayExternalInfo().externalFixedIps().size() > 0) { 147 + OpenstackRouter osRouter = openstackRouter(routerIface.id());
267 - checkExternalConnection(openstackRouter, getOpenstackRouterInterface(openstackRouter)); 148 + OpenstackPort osPort = openstackService.port(routerIface.portId());
268 - } else { 149 + if (osRouter == null || osPort == null) {
269 - unsetExternalConnection(); 150 + log.warn("Failed to add router interface {}", routerIface);
151 + return;
270 } 152 }
271 - }
272 -
273 - private void unsetExternalConnection() {
274 - Collection<OpenstackRouter> internalRouters = getExternalRouter(false);
275 - internalRouters.forEach(r ->
276 - getOpenstackRouterInterface(r).forEach(i -> rulePopulator.removeExternalRules(i)));
277 - }
278 153
279 - private Collection<OpenstackRouter> getExternalRouter(boolean externalConnection) { 154 + setRoutes(osRouter, Optional.empty());
280 - List<OpenstackRouter> routers; 155 + if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
281 - if (externalConnection) { 156 + setExternalConnection(osRouter, osPort.networkId());
282 - routers = openstackService.routers()
283 - .stream()
284 - .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() > 0))
285 - .collect(Collectors.toList());
286 - } else {
287 - routers = openstackService.routers()
288 - .stream()
289 - .filter(r -> (r.gatewayExternalInfo().externalFixedIps().size() == 0))
290 - .collect(Collectors.toList());
291 } 157 }
292 - return routers; 158 + log.info("Connected {} to router {}", osPort.fixedIps(), osRouter.name());
293 - }
294 -
295 - @Override
296 - public void deleteRouter(String id) {
297 - //TODO : In now, there`s nothing to do for deleteRouter process. It is reserved.
298 } 159 }
299 160
300 @Override 161 @Override
301 - public void updateRouterInterface(OpenstackRouterInterface routerInterface) { 162 + public void removeRouterInterface(OpenstackRouterInterface routerIface) {
302 - List<OpenstackRouterInterface> routerInterfaces = Lists.newArrayList(); 163 + OpenstackRouter osRouter = openstackService.router(routerIface.id());
303 - routerInterfaces.add(routerInterface); 164 + if (osRouter == null) {
304 - checkExternalConnection(getOpenstackRouter(routerInterface.id()), routerInterfaces); 165 + log.warn("Failed to remove router interface {}", routerIface);
305 - setL3Connection(getOpenstackRouter(routerInterface.id()), null);
306 - routerInterfaceMap.put(routerInterface.portId(), openstackService.port(routerInterface.portId()).networkId());
307 - }
308 -
309 - /**
310 - * Set flow rules for traffic between two different subnets when more than one subnets
311 - * connected to a router.
312 - *
313 - * @param openstackRouter OpenstackRouter Info
314 - * @param openstackPort OpenstackPort Info
315 - */
316 - private void setL3Connection(OpenstackRouter openstackRouter, OpenstackPort openstackPort) {
317 - Collection<OpenstackRouterInterface> interfaceList = getOpenstackRouterInterface(openstackRouter);
318 -
319 - if (interfaceList.size() < 2) {
320 return; 166 return;
321 } 167 }
322 - if (openstackPort == null) {
323 - interfaceList.forEach(i -> {
324 - OpenstackPort interfacePort = openstackService.port(i.portId());
325 - openstackService.ports()
326 - .stream()
327 - .filter(p -> p.networkId().equals(interfacePort.networkId())
328 - && !p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
329 - .forEach(p -> rulePopulator.populateL3Rules(p,
330 - getL3ConnectionList(p.networkId(), interfaceList)));
331 -
332 - });
333 - } else {
334 - rulePopulator.populateL3Rules(openstackPort, getL3ConnectionList(openstackPort.networkId(), interfaceList));
335 - }
336 168
337 - } 169 + OpenstackSubnet osSubnet = openstackService.subnet(routerIface.subnetId());
170 + OpenstackNetwork osNet = openstackService.network(osSubnet.networkId());
338 171
339 - private List<OpenstackRouterInterface> getL3ConnectionList(String networkId, 172 + unsetRoutes(osRouter, osNet);
340 - Collection<OpenstackRouterInterface> interfaceList) { 173 + if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
341 - List<OpenstackRouterInterface> targetList = Lists.newArrayList(); 174 + unsetExternalConnection(osRouter, osNet.id());
342 - interfaceList.forEach(i -> {
343 - OpenstackPort port = openstackService.port(i.portId());
344 - if (!port.networkId().equals(networkId)) {
345 - targetList.add(i);
346 - }
347 - });
348 - return targetList;
349 - }
350 -
351 - @Override
352 - public void removeRouterInterface(OpenstackRouterInterface routerInterface) {
353 - OpenstackRouter router = openstackService.router(routerInterface.id());
354 - Collection<OpenstackRouterInterface> interfaceList = getOpenstackRouterInterface(router);
355 - if (interfaceList.size() == 1) {
356 - List<OpenstackRouterInterface> newList = Lists.newArrayList();
357 - newList.add(routerInterface);
358 - interfaceList.forEach(i -> removeL3RulesForRouterInterface(i, router, newList));
359 } 175 }
360 - removeL3RulesForRouterInterface(routerInterface, router, null); 176 + log.info("Disconnected {} from router {}", osSubnet.cidr(), osRouter.name());
361 - rulePopulator.removeExternalRules(routerInterface);
362 - routerInterfaceMap.remove(routerInterface.portId());
363 } 177 }
364 178
365 - private void removeL3RulesForRouterInterface(OpenstackRouterInterface routerInterface, OpenstackRouter router, 179 + private void setExternalConnection(OpenstackRouter osRouter, String osNetId) {
366 - List<OpenstackRouterInterface> newList) { 180 + if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
367 - if (!routerInterfaceMap.containsKey(routerInterface.portId())) { 181 + log.debug("Source NAT is disabled");
368 - log.warn("No router interface information found for {}", routerInterface.portId());
369 return; 182 return;
370 } 183 }
371 - openstackService.ports(routerInterfaceMap.get(routerInterface.portId()).value()).forEach(p -> {
372 - Ip4Address vmIp = (Ip4Address) p.fixedIps().values().toArray()[0];
373 - if (newList == null) {
374 - rulePopulator.removeL3Rules(vmIp,
375 - getL3ConnectionList(p.networkId(), getOpenstackRouterInterface(router)));
376 - } else {
377 - rulePopulator.removeL3Rules(vmIp, newList);
378 - }
379 - }
380 - );
381 - }
382 184
383 - @Override 185 + // FIXME router interface is subnet specific, not network
384 - public String networkIdForRouterInterface(String portId) { 186 + OpenstackNetwork osNet = openstackService.network(osNetId);
385 - return routerInterfaceMap.get(portId).value(); 187 + populateExternalRules(osNet);
386 } 188 }
387 189
388 - private Collection<OpenstackFloatingIP> associatedFloatingIps() { 190 + private void unsetExternalConnection(OpenstackRouter osRouter, String osNetId) {
389 - List<OpenstackFloatingIP> fIps = Lists.newArrayList(); 191 + if (!osRouter.gatewayExternalInfo().isEnablePnat()) {
390 - floatingIpMap.values() 192 + log.debug("Source NAT is disabled");
391 - .stream() 193 + return;
392 - .filter(fIp -> fIp.value().portId() != null)
393 - .forEach(fIp -> fIps.add(fIp.value()));
394 - return fIps;
395 - }
396 -
397 - private void reloadInitL3Rules() {
398 -
399 - l3EventExecutorService.execute(() ->
400 - openstackService.ports()
401 - .stream()
402 - .forEach(p ->
403 - {
404 - if (p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE)) {
405 - updateRouterInterface(portToRouterInterface(p));
406 - } else {
407 - Optional<Ip4Address> vmIp = p.fixedIps().values().stream().findAny();
408 - if (vmIp.isPresent()) {
409 - OpenstackFloatingIP floatingIP = getOpenstackFloatingIp(vmIp.get());
410 - if (floatingIP != null) {
411 - updateFloatingIP(floatingIP);
412 - }
413 - }
414 - }
415 - })
416 - );
417 - }
418 -
419 - private OpenstackRouterInterface portToRouterInterface(OpenstackPort p) {
420 - OpenstackRouterInterface.Builder osBuilder = new OpenstackRouterInterface.Builder()
421 - .id(checkNotNull(p.deviceId()))
422 - .tenantId(checkNotNull(openstackService.network(p.networkId()).tenantId()))
423 - .subnetId(checkNotNull(p.fixedIps().keySet().stream().findFirst().orElse(null)).toString())
424 - .portId(checkNotNull(p.id()));
425 -
426 - return osBuilder.build();
427 - }
428 -
429 - private class InternalPacketProcessor implements PacketProcessor {
430 -
431 - @Override
432 - public void process(PacketContext context) {
433 -
434 - DeviceId senderDeviceId = context.inPacket().receivedFrom().deviceId();
435 - if (!nodeService.routerBridge(senderDeviceId).isPresent()) {
436 - log.warn("No router bridge for {} is found.", senderDeviceId);
437 - return;
438 - }
439 - if (context.isHandled()) {
440 - return;
441 - } else if (!checkGatewayNode(context.inPacket().receivedFrom().deviceId())) {
442 - return;
443 - }
444 -
445 - InboundPacket pkt = context.inPacket();
446 - Ethernet ethernet = pkt.parsed();
447 -
448 - //TODO: Considers IPv6 later.
449 - if (ethernet == null) {
450 - return;
451 - } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
452 - IPv4 iPacket = (IPv4) ethernet.getPayload();
453 - switch (iPacket.getProtocol()) {
454 - case IPv4.PROTOCOL_ICMP:
455 -
456 - icmpEventExecutorService.execute(() ->
457 - openstackIcmpHandler.processIcmpPacket(context, ethernet));
458 - break;
459 - case IPv4.PROTOCOL_UDP:
460 - // don't process DHCP
461 - UDP udpPacket = (UDP) iPacket.getPayload();
462 - if (udpPacket.getDestinationPort() == UDP.DHCP_SERVER_PORT &&
463 - udpPacket.getSourcePort() == UDP.DHCP_CLIENT_PORT) {
464 - break;
465 - }
466 - default:
467 - int portNum = getPortNum(ethernet.getSourceMAC(), iPacket.getDestinationAddress());
468 - DeviceId deviceId = pkt.receivedFrom().deviceId();
469 - Port port = null;
470 - port = deviceService.getPort(deviceId,
471 - gatewayService.getUplinkPort(deviceId));
472 - if (port != null) {
473 - OpenstackPort openstackPort = getOpenstackPort(ethernet.getSourceMAC(),
474 - Ip4Address.valueOf(iPacket.getSourceAddress()));
475 - l3EventExecutorService.execute(new OpenstackPnatHandler(rulePopulator, context,
476 - portNum, openstackPort, port));
477 -
478 - } else {
479 - log.warn("There`s no external interface");
480 - }
481 -
482 - break;
483 - }
484 - } else if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
485 - arpEventExecutorService.execute(() ->
486 - openstackArpHandler.processArpPacketFromRouter(context, ethernet));
487 - }
488 - }
489 -
490 - private int getPortNum(MacAddress sourceMac, int destinationAddress) {
491 - int portNum = findUnusedPortNum();
492 - if (portNum == 0) {
493 - clearPortNumMap();
494 - portNum = findUnusedPortNum();
495 - }
496 - tpPortNumMap.put(portNum, sourceMac.toString().concat(COLON).concat(String.valueOf(destinationAddress)));
497 - return portNum;
498 - }
499 -
500 - private int findUnusedPortNum() {
501 - for (int i = TP_PORT_MINIMUM_NUM; i < TP_PORT_MAXIMUM_NUM; i++) {
502 - if (!tpPortNumMap.containsKey(i)) {
503 - return i;
504 - }
505 - }
506 - return 0;
507 } 194 }
508 195
196 + // FIXME router interface is subnet specific, not network
197 + OpenstackNetwork osNet = openstackService.network(osNetId);
198 + removeExternalRules(osNet);
509 } 199 }
510 200
511 - private boolean checkGatewayNode(DeviceId deviceId) { 201 + private void setRoutes(OpenstackRouter osRouter, Optional<Host> host) {
512 - return gatewayService.getGatewayDeviceIds().contains(deviceId); 202 + Set<OpenstackNetwork> routableNets = routableNetworks(osRouter.id());
513 - } 203 + if (routableNets.size() < 2) {
514 - 204 + // no other subnet interface is connected to this router, do nothing
515 - private void clearPortNumMap() {
516 - tpPortNumMap.entrySet().forEach(e -> {
517 - if (System.currentTimeMillis() - e.getValue().creationTime() > PNAT_PORT_EXPIRE_TIME) {
518 - tpPortNumMap.remove(e.getKey());
519 - }
520 - });
521 - }
522 -
523 - private Optional<Port> getExternalPort(DeviceId deviceId, String interfaceName) {
524 - return deviceService.getPorts(deviceId)
525 - .stream()
526 - .filter(p -> p.annotations().value(PORT_NAME).equals(interfaceName))
527 - .findAny();
528 - }
529 -
530 - private void checkExternalConnection(OpenstackRouter router,
531 - Collection<OpenstackRouterInterface> interfaces) {
532 - checkNotNull(router, "Router can not be null");
533 - checkNotNull(interfaces, "routerInterfaces can not be null");
534 - Ip4Address externalIp = router.gatewayExternalInfo().externalFixedIps()
535 - .values().stream().findFirst().orElse(null);
536 - if ((externalIp == null) || (!router.gatewayExternalInfo().isEnablePnat())) {
537 - log.debug("Not satisfied to set pnat configuration");
538 return; 205 return;
539 } 206 }
540 - interfaces.forEach(this::initiateL3Rule);
541 - }
542 207
543 - private Optional<OpenstackRouter> getRouterfromExternalIp(Ip4Address externalIp) { 208 + // FIXME router interface is subnet specific, not network
544 - return getExternalRouter(true) 209 + Set<String> routableNetIds = routableNets.stream()
545 - .stream() 210 + .map(OpenstackNetwork::id)
546 - .filter(r -> r.gatewayExternalInfo() 211 + .collect(Collectors.toSet());
547 - .externalFixedIps() 212 +
548 - .values() 213 + Set<Host> hosts = host.isPresent() ? ImmutableSet.of(host.get()) :
549 - .stream() 214 + Tools.stream(hostService.getHosts())
550 - .findAny() 215 + .filter(h -> routableNetIds.contains(h.annotations().value(NETWORK_ID)))
551 - .get() 216 + .collect(Collectors.toSet());
552 - .equals(externalIp)) 217 +
553 - .findAny(); 218 + hosts.stream().forEach(h -> populateRoutingRules(h, routableNets));
219 + }
220 +
221 + private void unsetRoutes(OpenstackRouter osRouter, OpenstackNetwork osNet) {
222 + // FIXME router interface is subnet specific, not network
223 + Set<OpenstackNetwork> routableNets = routableNetworks(osRouter.id());
224 + Tools.stream(hostService.getHosts())
225 + .filter(h -> Objects.equals(
226 + h.annotations().value(NETWORK_ID), osNet.id()))
227 + .forEach(h -> removeRoutingRules(h, routableNets));
228 +
229 + routableNets.stream().forEach(n -> {
230 + Tools.stream(hostService.getHosts())
231 + .filter(h -> Objects.equals(
232 + h.annotations().value(NETWORK_ID),
233 + n.id()))
234 + .forEach(h -> removeRoutingRules(h, ImmutableSet.of(osNet)));
235 + log.debug("Removed between {} to {}", n.name(), osNet.name());
236 + });
554 } 237 }
555 238
556 - private void initiateL3Rule(OpenstackRouterInterface routerInterface) { 239 + private OpenstackRouter openstackRouter(String routerId) {
557 - long vni = Long.parseLong(openstackService.network(openstackService 240 + return openstackService.routers().stream().filter(r ->
558 - .port(routerInterface.portId()).networkId()).segmentId()); 241 + r.id().equals(routerId)).iterator().next();
559 - rulePopulator.populateExternalRules(vni);
560 } 242 }
561 243
562 - private Collection<OpenstackRouterInterface> getOpenstackRouterInterface(OpenstackRouter router) { 244 + private Optional<OpenstackPort> routerIfacePort(String osNetId) {
563 - List<OpenstackRouterInterface> interfaces = Lists.newArrayList(); 245 + // FIXME router interface is subnet specific, not network
564 - openstackService.ports() 246 + return openstackService.ports().stream()
565 - .stream() 247 + .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
566 - .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) 248 + p.networkId().equals(osNetId))
567 - && p.deviceId().equals(router.id())) 249 + .findAny();
568 - .forEach(p -> interfaces.add(portToRouterInterface(p)));
569 - return interfaces;
570 } 250 }
571 251
572 - private OpenstackRouter getOpenstackRouter(String id) { 252 + private Set<OpenstackNetwork> routableNetworks(String osRouterId) {
573 - return openstackService.routers().stream().filter(r -> 253 + // FIXME router interface is subnet specific, not network
574 - r.id().equals(id)).iterator().next(); 254 + return openstackService.ports().stream()
255 + .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) &&
256 + p.deviceId().equals(osRouterId))
257 + .map(p -> openstackService.network(p.networkId()))
258 + .collect(Collectors.toSet());
575 } 259 }
576 260
577 - private OpenstackPort getOpenstackPort(MacAddress sourceMac, Ip4Address ip4Address) { 261 + private void populateExternalRules(OpenstackNetwork osNet) {
578 - OpenstackPort openstackPort = openstackService.ports().stream() 262 + populateCnodeToGateway(Long.valueOf(osNet.segmentId()));
579 - .filter(p -> p.macAddress().equals(sourceMac)).iterator().next(); 263 + populateGatewayToController(Long.valueOf(osNet.segmentId()));
580 - return openstackPort.fixedIps().values().stream().filter(ip ->
581 - ip.equals(ip4Address)).count() > 0 ? openstackPort : null;
582 } 264 }
583 265
584 - private OpenstackFloatingIP getOpenstackFloatingIp(Ip4Address vmIp) { 266 + private void removeExternalRules(OpenstackNetwork osNet) {
585 - Optional<OpenstackFloatingIP> floatingIp = floatingIpMap.asJavaMap().values().stream() 267 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
586 - .filter(f -> f.portId() != null && f.fixedIpAddress().equals(vmIp)) 268 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
587 - .findAny(); 269 + .matchTunnelId(Long.valueOf(osNet.segmentId()))
270 + .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
588 271
589 - if (floatingIp.isPresent()) { 272 + nodeService.completeNodes().stream().forEach(node -> {
590 - return floatingIp.get(); 273 + ForwardingObjective.Flag flag = node.type().equals(GATEWAY) ?
591 - } 274 + ForwardingObjective.Flag.VERSATILE :
592 - log.debug("There is no floating IP information for VM IP {}", vmIp); 275 + ForwardingObjective.Flag.SPECIFIC;
593 276
594 - return null; 277 + RulePopulatorUtil.removeRule(
595 - } 278 + flowObjectiveService,
596 - 279 + appId,
597 - private Optional<OpenstackPort> getRouterInterfacePort(String networkId) { 280 + node.intBridge(),
598 - 281 + sBuilder.build(),
599 - return openstackService.ports() 282 + flag,
600 - .stream() 283 + ROUTING_RULE_PRIORITY);
601 - .filter(p -> p.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE) 284 + });
602 - && p.networkId().equals(networkId))
603 - .findAny();
604 } 285 }
605 286
606 - // TODO: Remove the function and the related codes when vRouter is running on different ONOS instance. 287 + private void populateRoutingRules(Host host, Set<OpenstackNetwork> osNets) {
607 - private void registerFloatingIpToHostService(OpenstackFloatingIP openstackFloatingIp, Action action) { 288 + String osNetId = host.annotations().value(NETWORK_ID);
608 - 289 + if (osNetId == null) {
609 - Optional<Host> hostOptional = hostService.getHostsByIp(openstackFloatingIp.fixedIpAddress())
610 - .stream()
611 - .findFirst();
612 - if (!hostOptional.isPresent()) {
613 - log.warn("No host with IP {} is registered and cannot add the floating IP. ",
614 - openstackFloatingIp.floatingIpAddress());
615 return; 290 return;
616 } 291 }
617 292
618 - Host host = hostOptional.get(); 293 + DeviceId localDevice = host.location().deviceId();
619 - Set<IpAddress> ipAddresses = Sets.newHashSet(); 294 + PortNumber localPort = host.location().port();
620 - if (action == Action.ASSOCIATE) { 295 + if (!nodeService.dataIp(localDevice).isPresent()) {
621 - ipAddresses.add(openstackFloatingIp.floatingIpAddress()); 296 + log.warn("Failed to populate L3 rules");
297 + return;
622 } 298 }
623 299
624 - HostDescription hostDescription = 300 + // TODO improve pipeline, do we have to install access rules between networks
625 - new DefaultHostDescription(host.mac(), host.vlan(), host.location(), ipAddresses, 301 + // for every single VMs?
626 - (DefaultAnnotations) host.annotations()); 302 + osNets.stream().filter(osNet -> !osNet.id().equals(osNetId)).forEach(osNet -> {
627 - 303 + populateRoutingRulestoSameNode(
628 - hostProviderService.hostDetected(host.id(), hostDescription, false); 304 + host.ipAddresses().stream().findFirst().get().getIp4Address(),
305 + host.mac(),
306 + localPort, localDevice,
307 + Long.valueOf(osNet.segmentId()));
308 +
309 + nodeService.completeNodes().stream()
310 + .filter(node -> node.type().equals(COMPUTE))
311 + .filter(node -> !node.intBridge().equals(localDevice))
312 + .forEach(node -> populateRoutingRulestoDifferentNode(
313 + host.ipAddresses().stream().findFirst().get().getIp4Address(),
314 + Long.valueOf(osNet.segmentId()),
315 + node.intBridge(),
316 + nodeService.dataIp(localDevice).get().getIp4Address()));
317 + });
629 } 318 }
630 319
631 - private class InternalHostListener implements HostListener { 320 + private void removeRoutingRules(Host host, Set<OpenstackNetwork> osNets) {
632 - 321 + String osNetId = host.annotations().value(NETWORK_ID);
633 - private void hostDetected(Host host) { 322 + if (osNetId == null) {
634 - String portId = host.annotations().value(Constants.PORT_ID); 323 + return;
635 - OpenstackPort openstackPort = openstackService.port(portId);
636 - if (openstackPort == null) {
637 - log.warn("No OpenstackPort information found from OpenStack for port ID {}", portId);
638 - return;
639 - }
640 -
641 - Optional<OpenstackPort> routerPort = getRouterInterfacePort(openstackPort.networkId());
642 - if (routerPort.isPresent()) {
643 - OpenstackRouterInterface routerInterface = portToRouterInterface(routerPort.get());
644 - l3EventExecutorService.execute(() ->
645 - setL3Connection(getOpenstackRouter(routerInterface.id()), openstackPort));
646 -
647 - }
648 } 324 }
649 325
650 - private void hostRemoved(Host host) { 326 + osNets.stream().filter(osNet -> !osNet.id().equals(osNetId)).forEach(osNet -> {
651 - String portId = host.annotations().value(Constants.PORT_ID); 327 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
652 - OpenstackPort openstackPort = openstackService.port(portId); 328 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
653 - if (openstackPort == null) { 329 + .matchIPDst(host.ipAddresses().stream().findFirst().get().toIpPrefix())
654 - log.warn("No OpenstackPort information found from OpenStack for port ID {}", portId); 330 + .matchTunnelId(Long.valueOf(osNet.segmentId()));
655 - return; 331 +
656 - } 332 + nodeService.completeNodes().stream()
333 + .filter(node -> node.type().equals(COMPUTE))
334 + .forEach(node -> RulePopulatorUtil.removeRule(
335 + flowObjectiveService,
336 + appId,
337 + node.intBridge(),
338 + sBuilder.build(),
339 + ForwardingObjective.Flag.SPECIFIC,
340 + ROUTING_RULE_PRIORITY));
341 + });
342 + log.debug("Removed routing rule from {} to {}", host, osNets);
343 + }
657 344
658 - Optional<OpenstackPort> routerPort = getRouterInterfacePort(openstackPort.networkId()); 345 + private void populateGatewayToController(long vni) {
659 - if (routerPort.isPresent()) { 346 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
660 - OpenstackRouterInterface routerInterface = portToRouterInterface(routerPort.get()); 347 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
661 - IpAddress ipAddress = host.ipAddresses().stream().findFirst().get(); 348 +
662 - l3EventExecutorService.execute(() -> rulePopulator.removeL3Rules(ipAddress.getIp4Address(), 349 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
663 - getL3ConnectionList(host.annotations().value(Constants.NETWORK_ID), 350 + .matchTunnelId(vni)
664 - getOpenstackRouterInterface(getOpenstackRouter(routerInterface.id()))))); 351 + .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
665 - } 352 + tBuilder.setOutput(PortNumber.CONTROLLER);
666 - } 353 +
354 + ForwardingObjective fo = DefaultForwardingObjective.builder()
355 + .withSelector(sBuilder.build())
356 + .withTreatment(tBuilder.build())
357 + .withFlag(ForwardingObjective.Flag.VERSATILE)
358 + .withPriority(ROUTING_RULE_PRIORITY)
359 + .fromApp(appId)
360 + .add();
361 +
362 + gatewayService.getGatewayDeviceIds().stream()
363 + .forEach(deviceId -> flowObjectiveService.forward(deviceId, fo));
364 + }
365 +
366 + private void populateCnodeToGateway(long vni) {
367 + nodeService.completeNodes().stream()
368 + .filter(node -> node.type().equals(COMPUTE))
369 + .forEach(node -> populateRuleToGateway(
370 + node.intBridge(),
371 + gatewayService.getGatewayGroupId(node.intBridge()),
372 + vni));
373 + }
374 +
375 + private void populateRuleToGateway(DeviceId deviceId, GroupId groupId, long vni) {
376 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
377 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
378 +
379 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
380 + .matchTunnelId(vni)
381 + .matchEthDst(Constants.DEFAULT_GATEWAY_MAC);
382 +
383 + tBuilder.group(groupId);
384 + ForwardingObjective fo = DefaultForwardingObjective.builder()
385 + .withSelector(sBuilder.build())
386 + .withTreatment(tBuilder.build())
387 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
388 + .withPriority(ROUTING_RULE_PRIORITY)
389 + .fromApp(appId)
390 + .add();
391 +
392 + flowObjectiveService.forward(deviceId, fo);
393 + }
394 +
395 + private void populateRoutingRulestoDifferentNode(Ip4Address vmIp, long vni,
396 + DeviceId deviceId, Ip4Address hostIp) {
397 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
398 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
399 +
400 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
401 + .matchTunnelId(vni)
402 + .matchIPDst(vmIp.toIpPrefix());
403 + tBuilder.extension(buildExtension(deviceService, deviceId, hostIp), deviceId)
404 + .setOutput(nodeService.tunnelPort(deviceId).get());
405 +
406 + ForwardingObjective fo = DefaultForwardingObjective.builder()
407 + .withSelector(sBuilder.build())
408 + .withTreatment(tBuilder.build())
409 + .withPriority(ROUTING_RULE_PRIORITY)
410 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
411 + .fromApp(appId)
412 + .add();
413 +
414 + flowObjectiveService.forward(deviceId, fo);
415 + }
416 +
417 + private void populateRoutingRulestoSameNode(Ip4Address vmIp, MacAddress vmMac,
418 + PortNumber port, DeviceId deviceId, long vni) {
419 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
420 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
421 +
422 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
423 + .matchIPDst(vmIp.toIpPrefix())
424 + .matchTunnelId(vni);
425 +
426 + tBuilder.setEthDst(vmMac)
427 + .setOutput(port);
428 +
429 + ForwardingObjective fo = DefaultForwardingObjective.builder()
430 + .withSelector(sBuilder.build())
431 + .withTreatment(tBuilder.build())
432 + .withPriority(ROUTING_RULE_PRIORITY)
433 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
434 + .fromApp(appId)
435 + .add();
436 +
437 + flowObjectiveService.forward(deviceId, fo);
438 + }
439 +
440 + private void reloadRoutingRules() {
441 + eventExecutor.execute(() -> openstackService.ports().stream()
442 + .filter(osPort -> osPort.deviceOwner().equals(DEVICE_OWNER_ROUTER_INTERFACE))
443 + .forEach(osPort -> {
444 + OpenstackRouter osRouter = openstackRouter(osPort.deviceId());
445 + setRoutes(osRouter, Optional.empty());
446 + if (osRouter.gatewayExternalInfo().externalFixedIps().size() > 0) {
447 + setExternalConnection(osRouter, osPort.networkId());
448 + }
449 + }));
450 + }
667 451
668 - private boolean isValidHost(Host host) { 452 + @Override
669 - return !host.ipAddresses().isEmpty() && 453 + protected void hostDetected(Host host) {
670 - host.annotations().value(Constants.VXLAN_ID) != null && 454 + String osNetId = host.annotations().value(NETWORK_ID);
671 - host.annotations().value(Constants.NETWORK_ID) != null && 455 + Optional<OpenstackPort> routerIface = routerIfacePort(osNetId);
672 - host.annotations().value(Constants.TENANT_ID) != null && 456 + if (!routerIface.isPresent()) {
673 - host.annotations().value(Constants.PORT_ID) != null; 457 + return;
674 } 458 }
459 + eventExecutor.execute(() -> setRoutes(
460 + openstackRouter(routerIface.get().deviceId()),
461 + Optional.of(host)));
462 + }
675 463
676 - @Override 464 + @Override
677 - public void event(HostEvent event) { 465 + protected void hostRemoved(Host host) {
678 - Host host = event.subject(); 466 + String osNetId = host.annotations().value(NETWORK_ID);
679 - if (!mastershipService.isLocalMaster(host.location().deviceId())) { 467 + Optional<OpenstackPort> routerIface = routerIfacePort(osNetId);
680 - // do not allow to proceed without mastership 468 + if (!routerIface.isPresent()) {
681 - return; 469 + return;
682 - }
683 -
684 - if (!isValidHost(host)) {
685 - log.debug("Invalid host event, ignore it {}", host);
686 - return;
687 - }
688 -
689 - switch (event.type()) {
690 - case HOST_UPDATED:
691 - case HOST_ADDED:
692 - l3EventExecutorService.execute(() -> hostDetected(host));
693 - break;
694 - case HOST_REMOVED:
695 - l3EventExecutorService.execute(() -> hostRemoved(host));
696 - break;
697 - default:
698 - break;
699 - }
700 } 470 }
471 + Set<OpenstackNetwork> routableNets = routableNetworks(routerIface.get().deviceId());
472 + eventExecutor.execute(() -> removeRoutingRules(host, routableNets));
701 } 473 }
702 474
703 - private class InternalOpenstackNodeListener implements OpenstackNodeListener { 475 + private class InternalNodeListener implements OpenstackNodeListener {
704 -
705 - private void nodeComplete() {
706 -
707 - rulePopulator = new OpenstackRoutingRulePopulator(appId, openstackService, flowObjectiveService,
708 - deviceService, driverService, nodeService, gatewayService);
709 - openstackIcmpHandler = new OpenstackIcmpHandler(packetService, deviceService, hostService,
710 - openstackService, nodeService, gatewayService);
711 - openstackArpHandler = new OpenstackRoutingArpHandler(packetService, openstackService, nodeService,
712 - gatewayService);
713 -
714 - // Packet handlers must be started AFTER all initialization processes.
715 - packetService.addProcessor(internalPacketProcessor, PacketProcessor.director(1));
716 -
717 - openstackIcmpHandler.requestPacket(appId);
718 - openstackArpHandler.requestPacket(appId);
719 -
720 - openstackService.floatingIps().stream()
721 - .forEach(f -> floatingIpMap.put(f.id(), f));
722 -
723 - reloadInitL3Rules();
724 - }
725 476
726 @Override 477 @Override
727 public void event(OpenstackNodeEvent event) { 478 public void event(OpenstackNodeEvent event) {
...@@ -730,28 +481,22 @@ public class OpenstackRoutingManager implements OpenstackRoutingService { ...@@ -730,28 +481,22 @@ public class OpenstackRoutingManager implements OpenstackRoutingService {
730 switch (event.type()) { 481 switch (event.type()) {
731 case COMPLETE: 482 case COMPLETE:
732 log.info("COMPLETE node {} detected", node.hostname()); 483 log.info("COMPLETE node {} detected", node.hostname());
733 - l3EventExecutorService.execute(() -> nodeComplete()); 484 + if (node.type() == GATEWAY) {
485 + GatewayNode gnode = GatewayNode.builder()
486 + .gatewayDeviceId(node.intBridge())
487 + .dataIpAddress(node.dataIp().getIp4Address())
488 + .uplinkIntf(node.externalPortName().get())
489 + .build();
490 + gatewayService.addGatewayNode(gnode);
491 + }
492 + eventExecutor.execute(OpenstackRoutingManager.this::reloadRoutingRules);
734 break; 493 break;
494 + case INIT:
495 + case DEVICE_CREATED:
735 case INCOMPLETE: 496 case INCOMPLETE:
736 - break;
737 default: 497 default:
738 break; 498 break;
739 } 499 }
740 } 500 }
741 } 501 }
742 -
743 - private class InternalHostProvider extends AbstractProvider implements HostProvider {
744 -
745 - /**
746 - * Creates a provider with the supplier identifier.
747 - */
748 - protected InternalHostProvider() {
749 - super(PID);
750 - }
751 -
752 - @Override
753 - public void triggerProbe(Host host) {
754 - // nothing to do
755 - }
756 - }
757 } 502 }
......
1 -/*
2 - * Copyright 2016-present 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 -package org.onosproject.openstacknetworking.routing;
17 -
18 -import com.google.common.collect.Lists;
19 -import org.onlab.packet.Ethernet;
20 -import org.onlab.packet.IPv4;
21 -import org.onlab.packet.Ip4Address;
22 -import org.onlab.packet.IpAddress;
23 -import org.onlab.packet.IpPrefix;
24 -import org.onlab.packet.MacAddress;
25 -import org.onlab.packet.TCP;
26 -import org.onlab.packet.TpPort;
27 -import org.onlab.packet.UDP;
28 -import org.onosproject.core.ApplicationId;
29 -import org.onosproject.core.GroupId;
30 -import org.onosproject.net.Device;
31 -import org.onosproject.net.DeviceId;
32 -import org.onosproject.net.Host;
33 -import org.onosproject.net.Port;
34 -import org.onosproject.net.PortNumber;
35 -import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
36 -import org.onosproject.net.device.DeviceService;
37 -import org.onosproject.net.driver.DefaultDriverData;
38 -import org.onosproject.net.driver.DefaultDriverHandler;
39 -import org.onosproject.net.driver.Driver;
40 -import org.onosproject.net.driver.DriverHandler;
41 -import org.onosproject.net.driver.DriverService;
42 -import org.onosproject.net.flow.DefaultTrafficSelector;
43 -import org.onosproject.net.flow.DefaultTrafficTreatment;
44 -import org.onosproject.net.flow.TrafficSelector;
45 -import org.onosproject.net.flow.TrafficTreatment;
46 -import org.onosproject.net.flow.instructions.ExtensionPropertyException;
47 -import org.onosproject.net.flow.instructions.ExtensionTreatment;
48 -import org.onosproject.net.flow.instructions.ExtensionTreatmentType;
49 -import org.onosproject.net.flowobjective.DefaultForwardingObjective;
50 -import org.onosproject.net.flowobjective.FlowObjectiveService;
51 -import org.onosproject.net.flowobjective.ForwardingObjective;
52 -import org.onosproject.net.packet.InboundPacket;
53 -import org.onosproject.openstackinterface.OpenstackInterfaceService;
54 -import org.onosproject.openstackinterface.OpenstackPort;
55 -import org.onosproject.openstackinterface.OpenstackRouterInterface;
56 -import org.onosproject.openstackinterface.OpenstackSubnet;
57 -import org.onosproject.openstackinterface.OpenstackFloatingIP;
58 -import org.onosproject.openstacknetworking.Constants;
59 -import org.onosproject.openstacknetworking.OpenstackRoutingService;
60 -import org.onosproject.scalablegateway.api.ScalableGatewayService;
61 -import org.onosproject.openstacknode.OpenstackNode;
62 -import org.onosproject.openstacknode.OpenstackNodeService;
63 -import org.slf4j.Logger;
64 -import org.slf4j.LoggerFactory;
65 -
66 -import java.util.List;
67 -import java.util.Optional;
68 -import java.util.stream.StreamSupport;
69 -
70 -import static com.google.common.base.Preconditions.checkNotNull;
71 -import static org.onlab.osgi.DefaultServiceDirectory.getService;
72 -import static org.onosproject.net.AnnotationKeys.PORT_NAME;
73 -
74 -/**
75 - * Populates Routing Flow Rules.
76 - */
77 -public class OpenstackRoutingRulePopulator {
78 -
79 - private final Logger log = LoggerFactory.getLogger(getClass());
80 -
81 - private final ApplicationId appId;
82 - private final FlowObjectiveService flowObjectiveService;
83 - private final OpenstackInterfaceService openstackService;
84 - private final DeviceService deviceService;
85 - private final DriverService driverService;
86 - private final ScalableGatewayService gatewayService;
87 - private final OpenstackNodeService nodeService;
88 -
89 - private static final String PORTNAME_PREFIX_TUNNEL = "vxlan";
90 - private static final String PORTNAME_PREFIX_VM = "tap";
91 -
92 - private static final String PORTNOTNULL = "Port can not be null";
93 - private static final String DEVICENOTNULL = "Device can not be null";
94 - private static final String TUNNEL_DESTINATION = "tunnelDst";
95 - private static final int ROUTING_RULE_PRIORITY = 25000;
96 - private static final int FLOATING_RULE_PRIORITY = 42000;
97 - private static final int PNAT_RULE_PRIORITY = 26000;
98 - private static final int PNAT_TIMEOUT = 120;
99 - private static final int PREFIX_LENGTH = 32;
100 -
101 - private InboundPacket inboundPacket;
102 - private OpenstackPort openstackPort;
103 - private int portNum;
104 - private MacAddress externalInterface;
105 - private MacAddress externalRouter;
106 -
107 - /**
108 - * The constructor of openstackRoutingRulePopulator.
109 - *
110 - * @param appId Caller`s appId
111 - * @param openstackService Opestack REST request handler
112 - * @param flowObjectiveService FlowObjectiveService
113 - * @param deviceService DeviceService
114 - * @param driverService DriverService
115 - * @param nodeService openstack node service
116 - * @param gatewayService scalable gateway service
117 - */
118 - public OpenstackRoutingRulePopulator(ApplicationId appId,
119 - OpenstackInterfaceService openstackService,
120 - FlowObjectiveService flowObjectiveService,
121 - DeviceService deviceService,
122 - DriverService driverService,
123 - OpenstackNodeService nodeService,
124 - ScalableGatewayService gatewayService) {
125 - this.appId = appId;
126 - this.flowObjectiveService = flowObjectiveService;
127 - this.openstackService = checkNotNull(openstackService);
128 - this.deviceService = deviceService;
129 - this.driverService = driverService;
130 - this.gatewayService = gatewayService;
131 - this.nodeService = nodeService;
132 - }
133 -
134 - /**
135 - * Populates flow rules for Pnat configurations.
136 - *
137 - * @param inboundPacket Packet-in event packet
138 - * @param openstackPort Target VM information
139 - * @param portNum Pnat port number
140 - * @param externalIp external ip address
141 - * @param externalInterfaceMacAddress Gateway external interface macaddress
142 - * @param externalRouterMacAddress Outer(physical) router`s macaddress
143 - */
144 - public void populatePnatFlowRules(InboundPacket inboundPacket, OpenstackPort openstackPort, int portNum,
145 - Ip4Address externalIp, MacAddress externalInterfaceMacAddress,
146 - MacAddress externalRouterMacAddress) {
147 - this.inboundPacket = inboundPacket;
148 - this.openstackPort = openstackPort;
149 - this.portNum = portNum;
150 - this.externalInterface = externalInterfaceMacAddress;
151 - this.externalRouter = externalRouterMacAddress;
152 -
153 - long vni = getVni(openstackPort.networkId());
154 -
155 - populatePnatIncomingFlowRules(vni, externalIp);
156 - populatePnatOutgoingFlowRules(vni, externalIp);
157 - }
158 -
159 - private void populatePnatOutgoingFlowRules(long vni, Ip4Address externalIp) {
160 - IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
161 -
162 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
163 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
164 - .matchIPProtocol(iPacket.getProtocol())
165 - .matchTunnelId(vni)
166 - .matchIPSrc(IpPrefix.valueOf(iPacket.getSourceAddress(), 32))
167 - .matchIPDst(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
168 -
169 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
170 -
171 - switch (iPacket.getProtocol()) {
172 - case IPv4.PROTOCOL_TCP:
173 - TCP tcpPacket = (TCP) iPacket.getPayload();
174 - sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getSourcePort()))
175 - .matchTcpDst(TpPort.tpPort(tcpPacket.getDestinationPort()));
176 - tBuilder.setTcpSrc(TpPort.tpPort(portNum));
177 - break;
178 - case IPv4.PROTOCOL_UDP:
179 - UDP udpPacket = (UDP) iPacket.getPayload();
180 - sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getSourcePort()))
181 - .matchUdpDst(TpPort.tpPort(udpPacket.getDestinationPort()));
182 - tBuilder.setUdpSrc(TpPort.tpPort(portNum));
183 - break;
184 - default:
185 - log.debug("Unsupported IPv4 protocol {}");
186 - break;
187 - }
188 -
189 - tBuilder.setIpSrc(externalIp);
190 - gatewayService.getGatewayNodes().forEach(node -> {
191 - tBuilder.setOutput(gatewayService.getUplinkPort(node.getGatewayDeviceId()));
192 - ForwardingObjective fo = DefaultForwardingObjective.builder()
193 - .withSelector(sBuilder.build())
194 - .withTreatment(tBuilder.build())
195 - .withFlag(ForwardingObjective.Flag.VERSATILE)
196 - .withPriority(PNAT_RULE_PRIORITY)
197 - .makeTemporary(PNAT_TIMEOUT)
198 - .fromApp(appId)
199 - .add();
200 -
201 - flowObjectiveService.forward(node.getGatewayDeviceId(), fo);
202 - });
203 -
204 - }
205 -
206 - private Port getPortOfExternalInterface() {
207 - return deviceService.getPorts(getGatewayNode().id()).stream()
208 - .filter(p -> p.annotations().value(PORT_NAME)
209 - .equals(org.onosproject.openstacknode.Constants.PATCH_INTG_BRIDGE))
210 - .findAny().orElse(null);
211 - }
212 -
213 -
214 - private void populatePnatIncomingFlowRules(long vni, Ip4Address externalIp) {
215 - IPv4 iPacket = (IPv4) inboundPacket.parsed().getPayload();
216 -
217 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
218 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
219 - .matchIPProtocol(iPacket.getProtocol())
220 - .matchIPDst(IpPrefix.valueOf(externalIp, 32))
221 - .matchIPSrc(IpPrefix.valueOf(iPacket.getDestinationAddress(), 32));
222 -
223 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
224 - tBuilder.setTunnelId(vni)
225 - .setEthDst(inboundPacket.parsed().getSourceMAC())
226 - .setIpDst(IpAddress.valueOf(iPacket.getSourceAddress()));
227 -
228 - switch (iPacket.getProtocol()) {
229 - case IPv4.PROTOCOL_TCP:
230 - TCP tcpPacket = (TCP) iPacket.getPayload();
231 - sBuilder.matchTcpSrc(TpPort.tpPort(tcpPacket.getDestinationPort()))
232 - .matchTcpDst(TpPort.tpPort(portNum));
233 - tBuilder.setTcpDst(TpPort.tpPort(tcpPacket.getSourcePort()));
234 - break;
235 - case IPv4.PROTOCOL_UDP:
236 - UDP udpPacket = (UDP) iPacket.getPayload();
237 - sBuilder.matchUdpSrc(TpPort.tpPort(udpPacket.getDestinationPort()))
238 - .matchUdpDst(TpPort.tpPort(portNum));
239 - tBuilder.setUdpDst(TpPort.tpPort(udpPacket.getSourcePort()));
240 - break;
241 - default:
242 - break;
243 - }
244 -
245 - getGatewayNodeList().forEach(node -> {
246 - DeviceId deviceId = node.id();
247 - tBuilder.extension(buildNiciraExtenstion(deviceId,
248 - getHostIpfromOpenstackPort(openstackPort).getIp4Address()), deviceId)
249 - .setOutput(getTunnelPort(deviceId));
250 -
251 - ForwardingObjective fo = DefaultForwardingObjective.builder()
252 - .withSelector(sBuilder.build())
253 - .withTreatment(tBuilder.build())
254 - .withFlag(ForwardingObjective.Flag.VERSATILE)
255 - .withPriority(PNAT_RULE_PRIORITY)
256 - .makeTemporary(PNAT_TIMEOUT)
257 - .fromApp(appId)
258 - .add();
259 -
260 - flowObjectiveService.forward(deviceId, fo);
261 - });
262 - }
263 -
264 - private List<Device> getGatewayNodeList() {
265 - List<Device> devices = Lists.newArrayList();
266 - gatewayService.getGatewayDeviceIds().forEach(deviceId ->
267 - devices.add(checkNotNull(deviceService.getDevice(deviceId))));
268 - return devices;
269 - }
270 -
271 - private IpAddress getHostIpfromOpenstackPort(OpenstackPort openstackPort) {
272 - Device device = getDevicefromOpenstackPort(openstackPort);
273 -
274 - Optional<IpAddress> ipAddress = nodeService.dataIp(device.id());
275 - if (!ipAddress.isPresent()) {
276 - log.warn("No IP address found for device {}", device.id());
277 - return null;
278 - }
279 -
280 - return ipAddress.get();
281 - }
282 -
283 - private Device getDevicefromOpenstackPort(OpenstackPort openstackPort) {
284 - String openstackPortName = PORTNAME_PREFIX_VM + openstackPort.id().substring(0, 11);
285 - Device device = StreamSupport.stream(deviceService.getDevices().spliterator(), false)
286 - .filter(d -> findPortinDevice(d.id(), openstackPortName))
287 - .iterator()
288 - .next();
289 - checkNotNull(device, DEVICENOTNULL);
290 - return device;
291 - }
292 -
293 - private boolean findPortinDevice(DeviceId deviceId, String openstackPortName) {
294 - Port port = deviceService.getPorts(deviceId)
295 - .stream()
296 - .filter(p -> p.isEnabled() && p.annotations().value(PORT_NAME).equals(openstackPortName))
297 - .findAny()
298 - .orElse(null);
299 - return port != null;
300 - }
301 -
302 - /**
303 - * Builds Nicira extension for tagging remoteIp of vxlan.
304 - *
305 - * @param deviceId Device Id of vxlan source device
306 - * @param hostIp Remote Ip of vxlan destination device
307 - * @return NiciraExtension Treatment
308 - */
309 - public ExtensionTreatment buildNiciraExtenstion(DeviceId deviceId, Ip4Address hostIp) {
310 - Driver driver = driverService.getDriver(deviceId);
311 - DriverHandler driverHandler = new DefaultDriverHandler(new DefaultDriverData(driver, deviceId));
312 - ExtensionTreatmentResolver resolver = driverHandler.behaviour(ExtensionTreatmentResolver.class);
313 -
314 - ExtensionTreatment extensionInstruction =
315 - resolver.getExtensionInstruction(
316 - ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST.type());
317 -
318 - try {
319 - extensionInstruction.setPropertyValue(TUNNEL_DESTINATION, hostIp);
320 - } catch (ExtensionPropertyException e) {
321 - log.error("Error setting Nicira extension setting {}", e);
322 - }
323 -
324 - return extensionInstruction;
325 - }
326 -
327 - /**
328 - * Returns port number of vxlan tunnel.
329 - *
330 - * @param deviceId Target Device Id
331 - * @return PortNumber
332 - */
333 - public PortNumber getTunnelPort(DeviceId deviceId) {
334 - Port port = deviceService.getPorts(deviceId).stream()
335 - .filter(p -> p.annotations().value(PORT_NAME).equals(PORTNAME_PREFIX_TUNNEL))
336 - .findAny().orElse(null);
337 -
338 - if (port == null) {
339 - log.error("No TunnelPort was created.");
340 - return null;
341 - }
342 - return port.number();
343 -
344 - }
345 -
346 - /**
347 - * Populates flow rules from openstackComputeNode to GatewayNode.
348 - *
349 - * @param vni Target network
350 - */
351 - public void populateExternalRules(long vni) {
352 -
353 - // 1. computeNode to gateway
354 - populateComputeNodeRules(vni);
355 - // 2. gatewayNode to controller
356 - populateRuleGatewaytoController(vni);
357 - }
358 -
359 - private void populateRuleGatewaytoController(long vni) {
360 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
361 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
362 -
363 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
364 - .matchTunnelId(vni)
365 - .matchEthDst(Constants.GATEWAY_MAC);
366 - tBuilder.setOutput(PortNumber.CONTROLLER);
367 -
368 - ForwardingObjective fo = DefaultForwardingObjective.builder()
369 - .withSelector(sBuilder.build())
370 - .withTreatment(tBuilder.build())
371 - .withFlag(ForwardingObjective.Flag.VERSATILE)
372 - .withPriority(ROUTING_RULE_PRIORITY)
373 - .fromApp(appId)
374 - .add();
375 -
376 - getGatewayNodeList().forEach(device -> flowObjectiveService.forward(device.id(), fo));
377 - }
378 -
379 - private void populateComputeNodeRules(long vni) {
380 - StreamSupport.stream(deviceService.getDevices().spliterator(), false)
381 - .filter(d -> isTypeOf(d.id(), OpenstackNodeService.NodeType.COMPUTE))
382 - .forEach(d -> populateRuleToGatewayBySgw(d.id(),
383 - gatewayService.getGatewayGroupId(d.id()), vni));
384 - }
385 -
386 - private void populateRuleToGatewayBySgw(DeviceId deviceId, GroupId groupId, long vni) {
387 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
388 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
389 -
390 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
391 - .matchTunnelId(vni)
392 - .matchEthDst(Constants.GATEWAY_MAC);
393 -
394 - tBuilder.group(groupId);
395 -
396 - ForwardingObjective fo = DefaultForwardingObjective.builder()
397 - .withSelector(sBuilder.build())
398 - .withTreatment(tBuilder.build())
399 - .withFlag(ForwardingObjective.Flag.SPECIFIC)
400 - .withPriority(ROUTING_RULE_PRIORITY)
401 - .fromApp(appId)
402 - .add();
403 -
404 - flowObjectiveService.forward(deviceId, fo);
405 - }
406 -
407 - private Device getGatewayNode() {
408 -
409 - // TODO Return the correct gateway node
410 - Optional<OpenstackNode> gwNode = nodeService.nodes().stream()
411 - .filter(n -> n.type().equals(OpenstackNodeService.NodeType.GATEWAY))
412 - .findFirst();
413 -
414 - if (!gwNode.isPresent()) {
415 - log.warn("No Gateway is defined.");
416 - return null;
417 - }
418 -
419 - return deviceService.getDevice(gwNode.get().intBridge());
420 - }
421 -
422 - private boolean isTypeOf(DeviceId deviceId, OpenstackNodeService.NodeType type) {
423 -
424 - Optional<OpenstackNode> node = nodeService.nodes().stream()
425 - .filter(n -> n.intBridge().equals(deviceId) ||
426 - (n.routerBridge().isPresent() && n.routerBridge().get().equals(deviceId)))
427 - .filter(n -> n.type().equals(type))
428 - .findFirst();
429 -
430 - if (node.isPresent()) {
431 - return true;
432 - }
433 -
434 - return false;
435 - }
436 -
437 - private long getVni(String netId) {
438 - return Long.parseLong(openstackService.network(netId).segmentId());
439 - }
440 -
441 - /**
442 - * Remove flow rules for external connection.
443 - *
444 - * @param routerInterface Corresponding routerInterface
445 - */
446 - public void removeExternalRules(OpenstackRouterInterface routerInterface) {
447 - OpenstackSubnet openstackSubnet = openstackService.subnet(routerInterface.subnetId());
448 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
449 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
450 - .matchTunnelId(getVni(openstackSubnet.networkId()))
451 - .matchEthDst(Constants.GATEWAY_MAC);
452 -
453 - StreamSupport.stream(deviceService.getDevices().spliterator(), false)
454 - .forEach(d -> {
455 - ForwardingObjective.Flag flag = isTypeOf(d.id(), OpenstackNodeService.NodeType.GATEWAY) ?
456 - ForwardingObjective.Flag.VERSATILE :
457 - ForwardingObjective.Flag.SPECIFIC;
458 - removeRule(d.id(), sBuilder, flag, ROUTING_RULE_PRIORITY);
459 - });
460 -
461 - }
462 -
463 - private void removeRule(DeviceId deviceId, TrafficSelector.Builder sBuilder,
464 - ForwardingObjective.Flag flag, int priority) {
465 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
466 -
467 - ForwardingObjective fo = DefaultForwardingObjective.builder()
468 - .withSelector(sBuilder.build())
469 - .withTreatment(tBuilder.build())
470 - .withFlag(flag)
471 - .withPriority(priority)
472 - .fromApp(appId)
473 - .remove();
474 -
475 - flowObjectiveService.forward(deviceId, fo);
476 - }
477 -
478 - /**
479 - * Populates flow rules for floatingIp configuration.
480 - *
481 - * @param floatingIP Corresponding floating ip information
482 - */
483 - public void populateFloatingIpRules(OpenstackFloatingIP floatingIP) {
484 - OpenstackPort port = openstackService.port(floatingIP.portId());
485 - //1. incoming rules
486 - populateFloatingIpIncomingRules(floatingIP, port);
487 - //2. outgoing rules
488 - populateFloatingIpOutgoingRules(floatingIP, port);
489 - }
490 -
491 - private void populateFloatingIpIncomingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
492 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
493 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
494 -
495 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
496 - .matchIPDst(IpPrefix.valueOf(floatingIP.floatingIpAddress(), PREFIX_LENGTH));
497 -
498 - DeviceId gatewayDeviceId = DeviceId.deviceId(port.deviceId());
499 - Optional<IpAddress> ipAddress = nodeService.dataIp(gatewayDeviceId);
500 - if (!ipAddress.isPresent()) {
501 - log.warn("No IP address found for device {}", port.deviceId());
502 - return;
503 - }
504 - tBuilder.setEthSrc(Constants.GATEWAY_MAC)
505 - .setEthDst(port.macAddress())
506 - .setIpDst(floatingIP.fixedIpAddress())
507 - .setTunnelId(getVni(port.networkId()))
508 - .extension(buildNiciraExtenstion(gatewayDeviceId,
509 - ipAddress.get().getIp4Address()), gatewayDeviceId)
510 - .setOutput(getTunnelPort(gatewayDeviceId));
511 -
512 - ForwardingObjective fo = DefaultForwardingObjective.builder()
513 - .withSelector(sBuilder.build())
514 - .withTreatment(tBuilder.build())
515 - .withFlag(ForwardingObjective.Flag.VERSATILE)
516 - .withPriority(FLOATING_RULE_PRIORITY)
517 - .fromApp(appId)
518 - .add();
519 -
520 - flowObjectiveService.forward(getGatewayNode().id(), fo);
521 - }
522 -
523 - private void populateFloatingIpOutgoingRules(OpenstackFloatingIP floatingIP, OpenstackPort port) {
524 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
525 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
526 -
527 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
528 - .matchTunnelId(getVni(port.networkId()))
529 - .matchIPSrc(IpPrefix.valueOf(floatingIP.fixedIpAddress(), 32));
530 -
531 - getGatewayNodeList().forEach(device -> {
532 - DeviceId deviceId = device.id();
533 - tBuilder.setIpSrc(floatingIP.floatingIpAddress())
534 - .setEthSrc(Constants.GW_EXT_INT_MAC)
535 - .setEthDst(Constants.PHY_ROUTER_MAC)
536 - .setOutput(getExternalPortNum(deviceId));
537 -
538 - ForwardingObjective fo = DefaultForwardingObjective.builder()
539 - .withSelector(sBuilder.build())
540 - .withTreatment(tBuilder.build())
541 - .withFlag(ForwardingObjective.Flag.VERSATILE)
542 - .withPriority(FLOATING_RULE_PRIORITY)
543 - .fromApp(appId)
544 - .add();
545 -
546 - flowObjectiveService.forward(deviceId, fo);
547 - });
548 - }
549 -
550 - private PortNumber getExternalPortNum(DeviceId deviceId) {
551 - return checkNotNull(gatewayService.getUplinkPort(deviceId), PORTNOTNULL);
552 - }
553 -
554 - /**
555 - * Removes flow rules for floating ip configuration.
556 - *
557 - * @param floatingIp Corresponding floating ip information
558 - * @param host host information for vm to remove
559 - */
560 - public void removeFloatingIpRules(OpenstackFloatingIP floatingIp, Host host) {
561 - TrafficSelector.Builder sOutgoingBuilder = DefaultTrafficSelector.builder();
562 - TrafficSelector.Builder sIncomingBuilder = DefaultTrafficSelector.builder();
563 -
564 - // XXX FloatingIp.tenant_id() == host.vxlan_id ???
565 - sOutgoingBuilder.matchEthType(Ethernet.TYPE_IPV4)
566 - .matchTunnelId(Integer.parseInt(host.annotations().value(Constants.VXLAN_ID)))
567 - .matchIPSrc(IpPrefix.valueOf(floatingIp.fixedIpAddress(), PREFIX_LENGTH));
568 -
569 - sIncomingBuilder.matchEthType(Ethernet.TYPE_IPV4)
570 - .matchIPDst(IpPrefix.valueOf(floatingIp.floatingIpAddress(), PREFIX_LENGTH));
571 -
572 - getGatewayNodeList().forEach(device -> {
573 - removeRule(device.id(), sOutgoingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
574 - removeRule(device.id(), sIncomingBuilder, ForwardingObjective.Flag.VERSATILE, FLOATING_RULE_PRIORITY);
575 - });
576 - }
577 -
578 - /**
579 - * Populates L3 rules for east to west traffic.
580 - *
581 - * @param openstackPort target VM
582 - * @param targetList target openstackRouterInterfaces
583 - */
584 - public void populateL3Rules(OpenstackPort openstackPort, List<OpenstackRouterInterface> targetList) {
585 - Device device = getDevicefromOpenstackPort(openstackPort);
586 - Port port = getPortFromOpenstackPort(device, openstackPort);
587 - Ip4Address vmIp = openstackPort.fixedIps().values().iterator().next();
588 -
589 - if (port == null) {
590 - return;
591 - }
592 -
593 - targetList.forEach(routerInterface -> {
594 - long vni = getVni(openstackService.port(routerInterface.portId()).networkId());
595 -
596 - if (vmIp == null) {
597 - return;
598 - }
599 -
600 - populateL3RulestoSameNode(vmIp, openstackPort, port, device, vni);
601 -
602 - deviceService.getAvailableDevices().forEach(d -> {
603 - if (!d.equals(device) && !d.equals(getGatewayNode())) {
604 - populateL3RulestoDifferentNode(vmIp, vni, d.id(),
605 - getHostIpfromOpenstackPort(openstackPort).getIp4Address());
606 - }
607 - });
608 - });
609 - }
610 -
611 - private void populateL3RulestoDifferentNode(Ip4Address vmIp, long vni, DeviceId deviceId, Ip4Address hostIp) {
612 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
613 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
614 -
615 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
616 - .matchTunnelId(vni)
617 - .matchIPDst(vmIp.toIpPrefix());
618 - tBuilder.extension(buildNiciraExtenstion(deviceId, hostIp), deviceId)
619 - .setOutput(getTunnelPort(deviceId));
620 -
621 - ForwardingObjective fo = DefaultForwardingObjective.builder()
622 - .withSelector(sBuilder.build())
623 - .withTreatment(tBuilder.build())
624 - .withPriority(ROUTING_RULE_PRIORITY)
625 - .withFlag(ForwardingObjective.Flag.SPECIFIC)
626 - .fromApp(appId)
627 - .add();
628 -
629 - flowObjectiveService.forward(deviceId, fo);
630 - }
631 -
632 - private void populateL3RulestoSameNode(Ip4Address vmIp, OpenstackPort p, Port port, Device device, long vni) {
633 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
634 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
635 -
636 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
637 - .matchIPDst(vmIp.toIpPrefix())
638 - .matchTunnelId(vni);
639 -
640 - tBuilder.setEthDst(p.macAddress())
641 - .setOutput(port.number());
642 -
643 - ForwardingObjective fo = DefaultForwardingObjective.builder()
644 - .withSelector(sBuilder.build())
645 - .withTreatment(tBuilder.build())
646 - .withPriority(ROUTING_RULE_PRIORITY)
647 - .withFlag(ForwardingObjective.Flag.SPECIFIC)
648 - .fromApp(appId)
649 - .add();
650 -
651 - flowObjectiveService.forward(device.id(), fo);
652 - }
653 -
654 - private Port getPortFromOpenstackPort(Device device, OpenstackPort p) {
655 - String openstackPortName = PORTNAME_PREFIX_VM + p.id().substring(0, 11);
656 - return deviceService.getPorts(device.id())
657 - .stream()
658 - .filter(pt -> pt.annotations().value(PORT_NAME).equals(openstackPortName))
659 - .findAny()
660 - .orElse(null);
661 - }
662 -
663 - /**
664 - * Removes L3 rules for routerInterface events.
665 - *
666 - * @param vmIp Corresponding Vm ip
667 - * @param routerInterfaces Corresponding routerInterfaces
668 - */
669 - public void removeL3Rules(Ip4Address vmIp, List<OpenstackRouterInterface> routerInterfaces) {
670 - if (vmIp == null) {
671 - return;
672 - }
673 -
674 - OpenstackRoutingService routingService = getService(OpenstackRoutingService.class);
675 -
676 - deviceService.getAvailableDevices().forEach(d -> {
677 - if (isTypeOf(d.id(), OpenstackNodeService.NodeType.COMPUTE)) {
678 - routerInterfaces.forEach(routerInterface -> {
679 - String networkId = routingService.networkIdForRouterInterface(routerInterface.portId());
680 - long vni = getVni(networkId);
681 -
682 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
683 -
684 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
685 - .matchIPDst(vmIp.toIpPrefix())
686 - .matchTunnelId(vni);
687 -
688 - removeRule(d.id(), sBuilder, ForwardingObjective.Flag.SPECIFIC, ROUTING_RULE_PRIORITY);
689 - });
690 - }
691 - });
692 - }
693 -}
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
15 */ 15 */
16 16
17 /** 17 /**
18 - * Application for OpenstackRouting. 18 + * Implements OpenStack L3 service plugin, which routes packets between subnets,
19 + * forwards packets from internal networks to external ones, and accesses instances
20 + * from external networks through floating IPs.
19 */ 21 */
20 -package org.onosproject.openstacknetworking.routing;
...\ No newline at end of file ...\ No newline at end of file
22 +package org.onosproject.openstacknetworking.routing;
......
...@@ -30,6 +30,7 @@ import org.onlab.packet.Ip4Address; ...@@ -30,6 +30,7 @@ import org.onlab.packet.Ip4Address;
30 import org.onlab.packet.IpPrefix; 30 import org.onlab.packet.IpPrefix;
31 import org.onlab.packet.TpPort; 31 import org.onlab.packet.TpPort;
32 import org.onlab.util.Tools; 32 import org.onlab.util.Tools;
33 +import org.onosproject.core.ApplicationId;
33 import org.onosproject.net.DeviceId; 34 import org.onosproject.net.DeviceId;
34 import org.onosproject.net.Host; 35 import org.onosproject.net.Host;
35 import org.onosproject.net.flow.DefaultTrafficSelector; 36 import org.onosproject.net.flow.DefaultTrafficSelector;
...@@ -43,6 +44,7 @@ import org.onosproject.openstackinterface.OpenstackPort; ...@@ -43,6 +44,7 @@ import org.onosproject.openstackinterface.OpenstackPort;
43 import org.onosproject.openstackinterface.OpenstackSecurityGroup; 44 import org.onosproject.openstackinterface.OpenstackSecurityGroup;
44 import org.onosproject.openstackinterface.OpenstackSecurityGroupRule; 45 import org.onosproject.openstackinterface.OpenstackSecurityGroupRule;
45 import org.onosproject.openstacknetworking.OpenstackSecurityGroupService; 46 import org.onosproject.openstacknetworking.OpenstackSecurityGroupService;
47 +import org.onosproject.openstacknetworking.AbstractVmHandler;
46 import org.slf4j.Logger; 48 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory; 49 import org.slf4j.LoggerFactory;
48 50
...@@ -60,7 +62,7 @@ import static org.onosproject.openstacknetworking.Constants.*; ...@@ -60,7 +62,7 @@ import static org.onosproject.openstacknetworking.Constants.*;
60 */ 62 */
61 @Component(immediate = true) 63 @Component(immediate = true)
62 @Service 64 @Service
63 -public class OpenstackSecurityGroupRulePopulator extends AbstractVmHandler 65 +public class OpenstackSecurityGroupManager extends AbstractVmHandler
64 implements OpenstackSecurityGroupService { 66 implements OpenstackSecurityGroupService {
65 67
66 private final Logger log = LoggerFactory.getLogger(getClass()); 68 private final Logger log = LoggerFactory.getLogger(getClass());
...@@ -77,10 +79,12 @@ public class OpenstackSecurityGroupRulePopulator extends AbstractVmHandler ...@@ -77,10 +79,12 @@ public class OpenstackSecurityGroupRulePopulator extends AbstractVmHandler
77 private static final String ETHTYPE_IPV4 = "IPV4"; 79 private static final String ETHTYPE_IPV4 = "IPV4";
78 80
79 private final Map<Host, Set<SecurityGroupRule>> securityGroupRuleMap = Maps.newConcurrentMap(); 81 private final Map<Host, Set<SecurityGroupRule>> securityGroupRuleMap = Maps.newConcurrentMap();
82 + private ApplicationId appId;
80 83
81 @Activate 84 @Activate
82 protected void activate() { 85 protected void activate() {
83 super.activate(); 86 super.activate();
87 + appId = coreService.registerApplication(SWITCHING_APP_ID);
84 } 88 }
85 89
86 @Deactivate 90 @Deactivate
...@@ -96,7 +100,7 @@ public class OpenstackSecurityGroupRulePopulator extends AbstractVmHandler ...@@ -96,7 +100,7 @@ public class OpenstackSecurityGroupRulePopulator extends AbstractVmHandler
96 100
97 Optional<Host> host = getVmByPortId(osPort.id()); 101 Optional<Host> host = getVmByPortId(osPort.id());
98 if (!host.isPresent()) { 102 if (!host.isPresent()) {
99 - log.warn("No host found with {}", osPort); 103 + log.debug("No host found with {}", osPort.id());
100 return; 104 return;
101 } 105 }
102 eventExecutor.execute(() -> updateSecurityGroupRules(host.get(), true)); 106 eventExecutor.execute(() -> updateSecurityGroupRules(host.get(), true));
......
...@@ -40,6 +40,7 @@ import org.onosproject.net.packet.PacketService; ...@@ -40,6 +40,7 @@ import org.onosproject.net.packet.PacketService;
40 import org.onosproject.openstackinterface.OpenstackInterfaceService; 40 import org.onosproject.openstackinterface.OpenstackInterfaceService;
41 import org.onosproject.openstackinterface.OpenstackNetwork; 41 import org.onosproject.openstackinterface.OpenstackNetwork;
42 import org.onosproject.openstackinterface.OpenstackPort; 42 import org.onosproject.openstackinterface.OpenstackPort;
43 +import org.onosproject.openstacknetworking.AbstractVmHandler;
43 import org.osgi.service.component.ComponentContext; 44 import org.osgi.service.component.ComponentContext;
44 import org.slf4j.Logger; 45 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory; 46 import org.slf4j.LoggerFactory;
...@@ -54,12 +55,11 @@ import static org.onosproject.openstacknetworking.Constants.*; ...@@ -54,12 +55,11 @@ import static org.onosproject.openstacknetworking.Constants.*;
54 * Handles ARP packet from VMs. 55 * Handles ARP packet from VMs.
55 */ 56 */
56 @Component(immediate = true) 57 @Component(immediate = true)
57 -public final class OpenstackArpHandler extends AbstractVmHandler { 58 +public final class OpenstackSwitchingArpHandler extends AbstractVmHandler {
58 59
59 private final Logger log = LoggerFactory.getLogger(getClass()); 60 private final Logger log = LoggerFactory.getLogger(getClass());
60 61
61 private static final String GATEWAY_MAC = "gatewayMac"; 62 private static final String GATEWAY_MAC = "gatewayMac";
62 - private static final String DEFAULT_GATEWAY_MAC = "1f:1f:1f:1f:1f:1f";
63 63
64 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 64 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
65 protected PacketService packetService; 65 protected PacketService packetService;
...@@ -67,9 +67,9 @@ public final class OpenstackArpHandler extends AbstractVmHandler { ...@@ -67,9 +67,9 @@ public final class OpenstackArpHandler extends AbstractVmHandler {
67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 67 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
68 protected OpenstackInterfaceService openstackService; 68 protected OpenstackInterfaceService openstackService;
69 69
70 - @Property(name = GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC, 70 + @Property(name = GATEWAY_MAC, value = DEFAULT_GATEWAY_MAC_STR,
71 label = "Fake MAC address for virtual network subnet gateway") 71 label = "Fake MAC address for virtual network subnet gateway")
72 - private String gatewayMac = DEFAULT_GATEWAY_MAC; 72 + private String gatewayMac = DEFAULT_GATEWAY_MAC_STR;
73 73
74 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor(); 74 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
75 private final Set<Ip4Address> gateways = Sets.newConcurrentHashSet(); 75 private final Set<Ip4Address> gateways = Sets.newConcurrentHashSet();
......
1 +/*
2 + * Copyright 2016-present 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 +package org.onosproject.openstacknetworking.switching;
17 +
18 +import com.google.common.base.Strings;
19 +import com.google.common.collect.Sets;
20 +import org.apache.felix.scr.annotations.Activate;
21 +import org.apache.felix.scr.annotations.Component;
22 +import org.apache.felix.scr.annotations.Deactivate;
23 +import org.apache.felix.scr.annotations.Reference;
24 +import org.apache.felix.scr.annotations.ReferenceCardinality;
25 +import org.apache.felix.scr.annotations.Service;
26 +import org.onlab.packet.Ip4Address;
27 +import org.onlab.packet.IpPrefix;
28 +import org.onlab.packet.VlanId;
29 +import org.onosproject.core.CoreService;
30 +import org.onosproject.dhcp.DhcpService;
31 +import org.onosproject.dhcp.IpAssignment;
32 +import org.onosproject.mastership.MastershipService;
33 +import org.onosproject.net.ConnectPoint;
34 +import org.onosproject.net.DefaultAnnotations;
35 +import org.onosproject.net.Device;
36 +import org.onosproject.net.Host;
37 +import org.onosproject.net.HostId;
38 +import org.onosproject.net.HostLocation;
39 +import org.onosproject.net.Port;
40 +import org.onosproject.net.device.DeviceEvent;
41 +import org.onosproject.net.device.DeviceListener;
42 +import org.onosproject.net.device.DeviceService;
43 +import org.onosproject.net.host.DefaultHostDescription;
44 +import org.onosproject.net.host.HostDescription;
45 +import org.onosproject.net.host.HostProvider;
46 +import org.onosproject.net.host.HostProviderRegistry;
47 +import org.onosproject.net.host.HostProviderService;
48 +import org.onosproject.net.host.HostService;
49 +import org.onosproject.net.provider.AbstractProvider;
50 +import org.onosproject.net.provider.ProviderId;
51 +import org.onosproject.openstackinterface.OpenstackInterfaceService;
52 +import org.onosproject.openstackinterface.OpenstackNetwork;
53 +import org.onosproject.openstackinterface.OpenstackPort;
54 +import org.onosproject.openstackinterface.OpenstackSubnet;
55 +import org.onosproject.openstacknode.OpenstackNode;
56 +import org.onosproject.openstacknode.OpenstackNodeEvent;
57 +import org.onosproject.openstacknode.OpenstackNodeListener;
58 +import org.onosproject.openstacknode.OpenstackNodeService;
59 +import org.slf4j.Logger;
60 +import org.slf4j.LoggerFactory;
61 +
62 +import java.util.Date;
63 +import java.util.Map;
64 +import java.util.concurrent.ExecutorService;
65 +import java.util.concurrent.Executors;
66 +
67 +import static org.onlab.util.Tools.groupedThreads;
68 +import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
69 +
70 +import static com.google.common.base.Preconditions.checkArgument;
71 +import static com.google.common.base.Preconditions.checkNotNull;
72 +import static org.onosproject.net.AnnotationKeys.PORT_NAME;
73 +import static org.onosproject.openstacknetworking.Constants.*;
74 +
75 +@Service
76 +@Component(immediate = true)
77 +public final class OpenstackSwitchingHostManager extends AbstractProvider
78 + implements HostProvider {
79 +
80 + private final Logger log = LoggerFactory.getLogger(getClass());
81 +
82 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
83 + protected CoreService coreService;
84 +
85 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 + protected DeviceService deviceService;
87 +
88 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 + protected HostProviderRegistry hostProviderRegistry;
90 +
91 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 + protected DhcpService dhcpService;
93 +
94 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 + protected HostService hostService;
96 +
97 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
98 + protected MastershipService mastershipService;
99 +
100 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
101 + protected OpenstackInterfaceService openstackService;
102 +
103 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
104 + protected OpenstackNodeService openstackNodeService;
105 +
106 + private final ExecutorService deviceEventExecutor =
107 + Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
108 + private final ExecutorService configEventExecutor =
109 + Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "config-event"));
110 + private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
111 + private final InternalOpenstackNodeListener internalNodeListener = new InternalOpenstackNodeListener();
112 +
113 + private HostProviderService hostProvider;
114 +
115 + /**
116 + * Creates OpenStack switching host provider.
117 + */
118 + public OpenstackSwitchingHostManager() {
119 + super(new ProviderId("host", SWITCHING_APP_ID));
120 + }
121 +
122 + @Activate
123 + protected void activate() {
124 + coreService.registerApplication(SWITCHING_APP_ID);
125 + deviceService.addListener(internalDeviceListener);
126 + openstackNodeService.addListener(internalNodeListener);
127 + hostProvider = hostProviderRegistry.register(this);
128 +
129 + log.info("Started");
130 + }
131 +
132 + @Deactivate
133 + protected void deactivate() {
134 + hostProviderRegistry.unregister(this);
135 + deviceService.removeListener(internalDeviceListener);
136 + openstackNodeService.removeListener(internalNodeListener);
137 +
138 + deviceEventExecutor.shutdown();
139 + configEventExecutor.shutdown();
140 +
141 + log.info("Stopped");
142 + }
143 +
144 + @Override
145 + public void triggerProbe(Host host) {
146 + // no probe is required
147 + }
148 +
149 + private void processPortAdded(Port port) {
150 + // TODO check the node state is COMPLETE
151 + OpenstackPort osPort = openstackService.port(port);
152 + if (osPort == null) {
153 + log.warn("Failed to get OpenStack port for {}", port);
154 + return;
155 + }
156 +
157 + OpenstackNetwork osNet = openstackService.network(osPort.networkId());
158 + if (osNet == null) {
159 + log.warn("Failed to get OpenStack network {}",
160 + osPort.networkId());
161 + return;
162 + }
163 +
164 + registerDhcpInfo(osPort);
165 + ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
166 + // TODO remove gateway IP from host annotation
167 + Map.Entry<String, Ip4Address> fixedIp = osPort.fixedIps().entrySet().stream().findFirst().get();
168 +
169 + // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the
170 + // existing instances.
171 + DefaultAnnotations.Builder annotations = DefaultAnnotations.builder()
172 + .set(NETWORK_ID, osPort.networkId())
173 + .set(SUBNET_ID, fixedIp.getKey())
174 + .set(PORT_ID, osPort.id())
175 + .set(VXLAN_ID, osNet.segmentId())
176 + .set(TENANT_ID, osNet.tenantId())
177 + // TODO remove gateway IP from host annotation
178 + .set(GATEWAY_IP, fixedIp.getValue().toString())
179 + .set(CREATE_TIME, String.valueOf(System.currentTimeMillis()));
180 +
181 + HostDescription hostDesc = new DefaultHostDescription(
182 + osPort.macAddress(),
183 + VlanId.NONE,
184 + new HostLocation(connectPoint, System.currentTimeMillis()),
185 + Sets.newHashSet(osPort.fixedIps().values()),
186 + annotations.build());
187 +
188 + HostId hostId = HostId.hostId(osPort.macAddress());
189 + hostProvider.hostDetected(hostId, hostDesc, false);
190 + }
191 +
192 + private void processPortRemoved(Port port) {
193 + ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number());
194 + removeHosts(connectPoint);
195 + }
196 +
197 + private void removeHosts(ConnectPoint connectPoint) {
198 + hostService.getConnectedHosts(connectPoint).stream()
199 + .forEach(host -> {
200 + dhcpService.removeStaticMapping(host.mac());
201 + hostProvider.hostVanished(host.id());
202 + });
203 + }
204 +
205 + private void registerDhcpInfo(OpenstackPort openstackPort) {
206 + checkNotNull(openstackPort);
207 + checkArgument(!openstackPort.fixedIps().isEmpty());
208 +
209 + OpenstackSubnet openstackSubnet = openstackService.subnets().stream()
210 + .filter(n -> n.networkId().equals(openstackPort.networkId()))
211 + .findFirst().orElse(null);
212 + if (openstackSubnet == null) {
213 + log.warn("Failed to find subnet for {}", openstackPort);
214 + return;
215 + }
216 +
217 + Ip4Address ipAddress = openstackPort.fixedIps().values().stream().findFirst().get();
218 + IpPrefix subnetPrefix = IpPrefix.valueOf(openstackSubnet.cidr());
219 + Ip4Address broadcast = Ip4Address.makeMaskedAddress(
220 + ipAddress,
221 + subnetPrefix.prefixLength());
222 +
223 + // TODO: supports multiple DNS servers
224 + Ip4Address domainServer = openstackSubnet.dnsNameservers().isEmpty() ?
225 + DNS_SERVER_IP : openstackSubnet.dnsNameservers().get(0);
226 +
227 + IpAssignment ipAssignment = IpAssignment.builder()
228 + .ipAddress(ipAddress)
229 + .leasePeriod(DHCP_INFINITE_LEASE)
230 + .timestamp(new Date())
231 + .subnetMask(Ip4Address.makeMaskPrefix(subnetPrefix.prefixLength()))
232 + .broadcast(broadcast)
233 + .domainServer(domainServer)
234 + .assignmentStatus(Option_RangeNotEnforced)
235 + .routerAddress(Ip4Address.valueOf(openstackSubnet.gatewayIp()))
236 + .build();
237 +
238 + dhcpService.setStaticMapping(openstackPort.macAddress(), ipAssignment);
239 + }
240 +
241 + private class InternalDeviceListener implements DeviceListener {
242 +
243 + @Override
244 + public void event(DeviceEvent event) {
245 + Device device = event.subject();
246 + if (!mastershipService.isLocalMaster(device.id())) {
247 + // do not allow to proceed without mastership
248 + return;
249 + }
250 +
251 + Port port = event.port();
252 + if (port == null) {
253 + return;
254 + }
255 +
256 + String portName = port.annotations().value(PORT_NAME);
257 + if (Strings.isNullOrEmpty(portName) ||
258 + !portName.startsWith(PORT_NAME_PREFIX_VM)) {
259 + // handles VM connected port event only
260 + return;
261 + }
262 +
263 + switch (event.type()) {
264 + case PORT_UPDATED:
265 + if (!event.port().isEnabled()) {
266 + deviceEventExecutor.execute(() -> processPortRemoved(event.port()));
267 + }
268 + break;
269 + case PORT_ADDED:
270 + deviceEventExecutor.execute(() -> processPortAdded(event.port()));
271 + break;
272 + default:
273 + break;
274 + }
275 + }
276 + }
277 +
278 + private class InternalOpenstackNodeListener implements OpenstackNodeListener {
279 +
280 + @Override
281 + public void event(OpenstackNodeEvent event) {
282 + OpenstackNode node = event.node();
283 + // TODO check leadership of the node and make only the leader process
284 +
285 + switch (event.type()) {
286 + case COMPLETE:
287 + log.info("COMPLETE node {} detected", node.hostname());
288 +
289 + // adds existing VMs running on the complete state node
290 + deviceService.getPorts(node.intBridge()).stream()
291 + .filter(port -> port.annotations().value(PORT_NAME)
292 + .startsWith(PORT_NAME_PREFIX_VM) &&
293 + port.isEnabled())
294 + .forEach(port -> {
295 + deviceEventExecutor.execute(() -> processPortAdded(port));
296 + log.info("VM is detected on {}", port);
297 + });
298 +
299 + // removes stale VMs
300 + hostService.getHosts().forEach(host -> {
301 + if (deviceService.getPort(host.location().deviceId(),
302 + host.location().port()) == null) {
303 + deviceEventExecutor.execute(() -> removeHosts(host.location()));
304 + log.info("Removed stale VM {}", host.location());
305 + }
306 + });
307 + break;
308 + case INCOMPLETE:
309 + log.warn("{} is changed to INCOMPLETE state", node);
310 + break;
311 + case INIT:
312 + case DEVICE_CREATED:
313 + default:
314 + break;
315 + }
316 + }
317 + }
318 +}
1 /* 1 /*
2 - * Copyright 2016-present Open Networking Laboratory 2 +* Copyright 2016-present Open Networking Laboratory
3 - * 3 +*
4 - * Licensed under the Apache License, Version 2.0 (the "License"); 4 +* Licensed under the Apache License, Version 2.0 (the "License");
5 - * you may not use this file except in compliance with 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 6 +* You may obtain a copy of the License at
7 - * 7 +*
8 - * http://www.apache.org/licenses/LICENSE-2.0 8 +* http://www.apache.org/licenses/LICENSE-2.0
9 - * 9 +*
10 - * Unless required by applicable law or agreed to in writing, software 10 +* Unless required by applicable law or agreed to in writing, software
11 - * distributed under the License is distributed on an "AS IS" BASIS, 11 +* distributed under the License is distributed on an "AS IS" BASIS,
12 - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 - * See the License for the specific language governing permissions and 13 +* See the License for the specific language governing permissions and
14 - * limitations under the License. 14 +* limitations under the License.
15 - */ 15 +*/
16 +
16 package org.onosproject.openstacknetworking.switching; 17 package org.onosproject.openstacknetworking.switching;
17 18
18 -import com.google.common.base.Strings;
19 -import com.google.common.collect.Sets;
20 import org.apache.felix.scr.annotations.Activate; 19 import org.apache.felix.scr.annotations.Activate;
21 import org.apache.felix.scr.annotations.Component; 20 import org.apache.felix.scr.annotations.Component;
22 import org.apache.felix.scr.annotations.Deactivate; 21 import org.apache.felix.scr.annotations.Deactivate;
23 import org.apache.felix.scr.annotations.Reference; 22 import org.apache.felix.scr.annotations.Reference;
24 import org.apache.felix.scr.annotations.ReferenceCardinality; 23 import org.apache.felix.scr.annotations.ReferenceCardinality;
25 -import org.apache.felix.scr.annotations.Service; 24 +import org.onlab.packet.Ethernet;
26 import org.onlab.packet.Ip4Address; 25 import org.onlab.packet.Ip4Address;
27 -import org.onlab.packet.IpPrefix; 26 +import org.onlab.packet.IpAddress;
28 -import org.onlab.packet.VlanId; 27 +import org.onosproject.core.ApplicationId;
29 -import org.onosproject.core.CoreService; 28 +import org.onosproject.net.DeviceId;
30 -import org.onosproject.dhcp.DhcpService;
31 -import org.onosproject.dhcp.IpAssignment;
32 -import org.onosproject.mastership.MastershipService;
33 -import org.onosproject.net.ConnectPoint;
34 -import org.onosproject.net.DefaultAnnotations;
35 -import org.onosproject.net.Device;
36 import org.onosproject.net.Host; 29 import org.onosproject.net.Host;
37 -import org.onosproject.net.HostId; 30 +import org.onosproject.net.PortNumber;
38 -import org.onosproject.net.HostLocation;
39 -import org.onosproject.net.Port;
40 -import org.onosproject.net.device.DeviceEvent;
41 -import org.onosproject.net.device.DeviceListener;
42 import org.onosproject.net.device.DeviceService; 31 import org.onosproject.net.device.DeviceService;
43 -import org.onosproject.net.host.DefaultHostDescription; 32 +import org.onosproject.net.flow.DefaultTrafficSelector;
44 -import org.onosproject.net.host.HostDescription; 33 +import org.onosproject.net.flow.DefaultTrafficTreatment;
45 -import org.onosproject.net.host.HostProvider; 34 +import org.onosproject.net.flow.TrafficSelector;
46 -import org.onosproject.net.host.HostProviderRegistry; 35 +import org.onosproject.net.flow.TrafficTreatment;
47 -import org.onosproject.net.host.HostProviderService; 36 +import org.onosproject.net.flowobjective.DefaultForwardingObjective;
48 -import org.onosproject.net.host.HostService; 37 +import org.onosproject.net.flowobjective.FlowObjectiveService;
49 -import org.onosproject.net.provider.AbstractProvider; 38 +import org.onosproject.net.flowobjective.ForwardingObjective;
50 -import org.onosproject.net.provider.ProviderId; 39 +import org.onosproject.openstacknetworking.AbstractVmHandler;
51 -import org.onosproject.openstackinterface.OpenstackInterfaceService;
52 -import org.onosproject.openstackinterface.OpenstackNetwork;
53 -import org.onosproject.openstackinterface.OpenstackPort;
54 -import org.onosproject.openstackinterface.OpenstackSubnet;
55 -import org.onosproject.openstacknode.OpenstackNode;
56 -import org.onosproject.openstacknode.OpenstackNodeEvent;
57 -import org.onosproject.openstacknode.OpenstackNodeListener;
58 import org.onosproject.openstacknode.OpenstackNodeService; 40 import org.onosproject.openstacknode.OpenstackNodeService;
59 import org.slf4j.Logger; 41 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory; 42 import org.slf4j.LoggerFactory;
61 43
62 -import java.util.Date; 44 +import java.util.Objects;
63 -import java.util.concurrent.ExecutorService; 45 +import java.util.Optional;
64 -import java.util.concurrent.Executors;
65 46
66 -import static org.onlab.util.Tools.groupedThreads;
67 -import static org.onosproject.dhcp.IpAssignment.AssignmentStatus.Option_RangeNotEnforced;
68 -
69 -import static com.google.common.base.Preconditions.checkArgument;
70 -import static com.google.common.base.Preconditions.checkNotNull;
71 -import static org.onosproject.net.AnnotationKeys.PORT_NAME;
72 import static org.onosproject.openstacknetworking.Constants.*; 47 import static org.onosproject.openstacknetworking.Constants.*;
48 +import static org.onosproject.openstacknetworking.RulePopulatorUtil.buildExtension;
73 49
74 -@Service
75 -@Component(immediate = true)
76 /** 50 /**
77 - * Populates forwarding rules for VMs created by Openstack. 51 + * Populates switching flow rules.
78 */ 52 */
79 -public final class OpenstackSwitchingManager extends AbstractProvider 53 +@Component(immediate = true)
80 - implements HostProvider { 54 +public final class OpenstackSwitchingManager extends AbstractVmHandler {
81 55
82 private final Logger log = LoggerFactory.getLogger(getClass()); 56 private final Logger log = LoggerFactory.getLogger(getClass());
83 57
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 58 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 - protected CoreService coreService;
86 -
87 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected DeviceService deviceService; 59 protected DeviceService deviceService;
89 60
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 61 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 - protected HostProviderRegistry hostProviderRegistry; 62 + protected FlowObjectiveService flowObjectiveService;
92 63
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 64 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 - protected DhcpService dhcpService; 65 + protected OpenstackNodeService nodeService;
95 66
96 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 67 + private ApplicationId appId;
97 - protected HostService hostService;
98 -
99 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 - protected MastershipService mastershipService;
101 -
102 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
103 - protected OpenstackInterfaceService openstackService;
104 -
105 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 - protected OpenstackNodeService openstackNodeService;
107 -
108 - private final ExecutorService deviceEventExecutor =
109 - Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "device-event"));
110 - private final ExecutorService configEventExecutor =
111 - Executors.newSingleThreadExecutor(groupedThreads("onos/openstackswitching", "config-event"));
112 - private final InternalDeviceListener internalDeviceListener = new InternalDeviceListener();
113 - private final InternalOpenstackNodeListener internalNodeListener = new InternalOpenstackNodeListener();
114 -
115 - private HostProviderService hostProvider;
116 -
117 - /**
118 - * Creates OpenStack switching host provider.
119 - */
120 - public OpenstackSwitchingManager() {
121 - super(new ProviderId("host", APP_ID));
122 - }
123 68
124 @Activate 69 @Activate
125 protected void activate() { 70 protected void activate() {
126 - coreService.registerApplication(APP_ID); 71 + super.activate();
127 - deviceService.addListener(internalDeviceListener); 72 + appId = coreService.registerApplication(SWITCHING_APP_ID);
128 - openstackNodeService.addListener(internalNodeListener);
129 - hostProvider = hostProviderRegistry.register(this);
130 -
131 - log.info("Started");
132 } 73 }
133 74
134 @Deactivate 75 @Deactivate
135 protected void deactivate() { 76 protected void deactivate() {
136 - hostProviderRegistry.unregister(this); 77 + super.deactivate();
137 - deviceService.removeListener(internalDeviceListener); 78 + }
138 - openstackNodeService.removeListener(internalNodeListener);
139 79
140 - deviceEventExecutor.shutdown(); 80 + private void populateSwitchingRules(Host host) {
141 - configEventExecutor.shutdown(); 81 + populateFlowRulesForTunnelTag(host);
82 + populateFlowRulesForTrafficToSameCnode(host);
83 + populateFlowRulesForTrafficToDifferentCnode(host);
142 84
143 - log.info("Stopped"); 85 + log.debug("Populated switching rule for {}", host);
144 } 86 }
145 87
146 - @Override 88 + private void populateFlowRulesForTunnelTag(Host host) {
147 - public void triggerProbe(Host host) { 89 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
148 - // no probe is required 90 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
91 +
92 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
93 + .matchInPort(host.location().port());
94 +
95 + tBuilder.setTunnelId(Long.valueOf(getVni(host)));
96 +
97 + ForwardingObjective fo = DefaultForwardingObjective.builder()
98 + .withSelector(sBuilder.build())
99 + .withTreatment(tBuilder.build())
100 + .withPriority(TUNNELTAG_RULE_PRIORITY)
101 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
102 + .fromApp(appId)
103 + .add();
104 +
105 + flowObjectiveService.forward(host.location().deviceId(), fo);
149 } 106 }
150 107
151 - private void processPortAdded(Port port) { 108 + private void populateFlowRulesForTrafficToSameCnode(Host host) {
152 - // TODO check the node state is COMPLETE 109 + //For L2 Switching Case
153 - OpenstackPort osPort = openstackService.port(port); 110 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
154 - if (osPort == null) { 111 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
155 - log.warn("Failed to get OpenStack port for {}", port); 112 +
113 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
114 + .matchIPDst(getIp(host).toIpPrefix())
115 + .matchTunnelId(Long.valueOf(getVni(host)));
116 +
117 + tBuilder.setOutput(host.location().port());
118 +
119 + ForwardingObjective fo = DefaultForwardingObjective.builder()
120 + .withSelector(sBuilder.build())
121 + .withTreatment(tBuilder.build())
122 + .withPriority(SWITCHING_RULE_PRIORITY)
123 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
124 + .fromApp(appId)
125 + .add();
126 +
127 + flowObjectiveService.forward(host.location().deviceId(), fo);
128 + }
129 +
130 + private void populateFlowRulesForTrafficToDifferentCnode(Host host) {
131 + Ip4Address localVmIp = getIp(host);
132 + DeviceId localDeviceId = host.location().deviceId();
133 + Optional<IpAddress> localDataIp = nodeService.dataIp(localDeviceId);
134 +
135 + if (!localDataIp.isPresent()) {
136 + log.debug("Failed to get data IP for device {}",
137 + host.location().deviceId());
156 return; 138 return;
157 } 139 }
158 140
159 - OpenstackNetwork osNet = openstackService.network(osPort.networkId()); 141 + String vni = getVni(host);
160 - if (osNet == null) { 142 + getVmsInDifferentCnode(host).forEach(remoteVm -> {
161 - log.warn("Failed to get OpenStack network {}", 143 + Optional<IpAddress> remoteDataIp = nodeService.dataIp(remoteVm.location().deviceId());
162 - osPort.networkId()); 144 + if (remoteDataIp.isPresent()) {
145 + setVxLanFlowRule(vni,
146 + localDeviceId,
147 + remoteDataIp.get().getIp4Address(),
148 + getIp(remoteVm));
149 +
150 + setVxLanFlowRule(vni,
151 + remoteVm.location().deviceId(),
152 + localDataIp.get().getIp4Address(),
153 + localVmIp);
154 + }
155 + });
156 + }
157 +
158 + private void setVxLanFlowRule(String vni, DeviceId deviceId, Ip4Address remoteIp,
159 + Ip4Address vmIp) {
160 + Optional<PortNumber> tunnelPort = nodeService.tunnelPort(deviceId);
161 + if (!tunnelPort.isPresent()) {
162 + log.warn("Failed to get tunnel port from {}", deviceId);
163 return; 163 return;
164 } 164 }
165 165
166 - registerDhcpInfo(osPort); 166 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
167 - ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number()); 167 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
168 - // TODO remove this and openstackPortInfo 168 +
169 - String gatewayIp = osNet.subnets().stream().findFirst().get().gatewayIp(); 169 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
170 - 170 + .matchTunnelId(Long.parseLong(vni))
171 - // Added CREATE_TIME intentionally to trigger HOST_UPDATED event for the 171 + .matchIPDst(vmIp.toIpPrefix());
172 - // existing instances. 172 + tBuilder.extension(buildExtension(deviceService, deviceId, remoteIp), deviceId)
173 - DefaultAnnotations.Builder annotations = DefaultAnnotations.builder() 173 + .setOutput(tunnelPort.get());
174 - .set(NETWORK_ID, osPort.networkId())
175 - .set(PORT_ID, osPort.id())
176 - .set(VXLAN_ID, osNet.segmentId())
177 - .set(TENANT_ID, osNet.tenantId())
178 - // TODO remove this and openstackPortInfo
179 - .set(GATEWAY_IP, gatewayIp)
180 - .set(CREATE_TIME, String.valueOf(System.currentTimeMillis()));
181 -
182 - HostDescription hostDesc = new DefaultHostDescription(
183 - osPort.macAddress(),
184 - VlanId.NONE,
185 - new HostLocation(connectPoint, System.currentTimeMillis()),
186 - Sets.newHashSet(osPort.fixedIps().values()),
187 - annotations.build());
188 -
189 - HostId hostId = HostId.hostId(osPort.macAddress());
190 - hostProvider.hostDetected(hostId, hostDesc, false);
191 - }
192 174
193 - private void processPortRemoved(Port port) { 175 + ForwardingObjective fo = DefaultForwardingObjective.builder()
194 - ConnectPoint connectPoint = new ConnectPoint(port.element().id(), port.number()); 176 + .withSelector(sBuilder.build())
195 - removeHosts(connectPoint); 177 + .withTreatment(tBuilder.build())
178 + .withPriority(SWITCHING_RULE_PRIORITY)
179 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
180 + .fromApp(appId)
181 + .add();
182 +
183 + flowObjectiveService.forward(deviceId, fo);
196 } 184 }
197 185
198 - private void removeHosts(ConnectPoint connectPoint) { 186 + private void removeSwitchingRules(Host host) {
199 - hostService.getConnectedHosts(connectPoint).stream() 187 + removeFlowRuleForTunnelTag(host);
200 - .forEach(host -> { 188 + removeFlowRuleForVMsInSameCnode(host);
201 - dhcpService.removeStaticMapping(host.mac()); 189 + removeFlowRuleForVMsInDiffrentCnode(host);
202 - hostProvider.hostVanished(host.id()); 190 +
203 - }); 191 + log.debug("Removed switching rule for {}", host);
204 } 192 }
205 193
206 - private void registerDhcpInfo(OpenstackPort openstackPort) { 194 + private void removeFlowRuleForTunnelTag(Host host) {
207 - checkNotNull(openstackPort); 195 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
208 - checkArgument(!openstackPort.fixedIps().isEmpty()); 196 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
209 197
210 - OpenstackSubnet openstackSubnet = openstackService.subnets().stream() 198 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
211 - .filter(n -> n.networkId().equals(openstackPort.networkId())) 199 + .matchInPort(host.location().port());
212 - .findFirst().orElse(null); 200 +
213 - if (openstackSubnet == null) { 201 + ForwardingObjective fo = DefaultForwardingObjective.builder()
214 - log.warn("Failed to find subnet for {}", openstackPort); 202 + .withSelector(sBuilder.build())
215 - return; 203 + .withTreatment(tBuilder.build())
216 - } 204 + .withPriority(TUNNELTAG_RULE_PRIORITY)
205 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
206 + .fromApp(appId)
207 + .remove();
208 +
209 + flowObjectiveService.forward(host.location().deviceId(), fo);
210 + }
217 211
218 - Ip4Address ipAddress = openstackPort.fixedIps().values().stream().findFirst().get(); 212 + private void removeFlowRuleForVMsInSameCnode(Host host) {
219 - IpPrefix subnetPrefix = IpPrefix.valueOf(openstackSubnet.cidr()); 213 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
220 - Ip4Address broadcast = Ip4Address.makeMaskedAddress( 214 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
221 - ipAddress, 215 + .matchIPDst(getIp(host).toIpPrefix())
222 - subnetPrefix.prefixLength()); 216 + .matchTunnelId(Long.valueOf(getVni(host)));
223 - 217 +
224 - // TODO: supports multiple DNS servers 218 + ForwardingObjective fo = DefaultForwardingObjective.builder()
225 - Ip4Address domainServer = openstackSubnet.dnsNameservers().isEmpty() ? 219 + .withSelector(sBuilder.build())
226 - DNS_SERVER_IP : openstackSubnet.dnsNameservers().get(0); 220 + .withTreatment(DefaultTrafficTreatment.builder().build())
227 - 221 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
228 - IpAssignment ipAssignment = IpAssignment.builder() 222 + .withPriority(SWITCHING_RULE_PRIORITY)
229 - .ipAddress(ipAddress) 223 + .fromApp(appId)
230 - .leasePeriod(DHCP_INFINITE_LEASE) 224 + .remove();
231 - .timestamp(new Date()) 225 +
232 - .subnetMask(Ip4Address.makeMaskPrefix(subnetPrefix.prefixLength())) 226 + flowObjectiveService.forward(host.location().deviceId(), fo);
233 - .broadcast(broadcast)
234 - .domainServer(domainServer)
235 - .assignmentStatus(Option_RangeNotEnforced)
236 - .routerAddress(Ip4Address.valueOf(openstackSubnet.gatewayIp()))
237 - .build();
238 -
239 - dhcpService.setStaticMapping(openstackPort.macAddress(), ipAssignment);
240 } 227 }
241 228
242 - private class InternalDeviceListener implements DeviceListener { 229 + private void removeFlowRuleForVMsInDiffrentCnode(Host host) {
230 + DeviceId deviceId = host.location().deviceId();
231 + final boolean anyPortRemainedInSameCnode = hostService.getConnectedHosts(deviceId)
232 + .stream()
233 + .filter(this::isValidHost)
234 + .anyMatch(h -> Objects.equals(getVni(h), getVni(host)));
235 +
236 + getVmsInDifferentCnode(host).forEach(h -> {
237 + removeVxLanFlowRule(h.location().deviceId(), getIp(host), getVni(host));
238 + if (!anyPortRemainedInSameCnode) {
239 + removeVxLanFlowRule(deviceId, getIp(h), getVni(host));
240 + }
241 + });
242 + }
243 243
244 - @Override 244 + private void removeVxLanFlowRule(DeviceId deviceId, Ip4Address vmIp, String vni) {
245 - public void event(DeviceEvent event) { 245 + TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
246 - Device device = event.subject();
247 - if (!mastershipService.isLocalMaster(device.id())) {
248 - // do not allow to proceed without mastership
249 - return;
250 - }
251 246
252 - Port port = event.port(); 247 + sBuilder.matchEthType(Ethernet.TYPE_IPV4)
253 - if (port == null) { 248 + .matchTunnelId(Long.valueOf(vni))
254 - return; 249 + .matchIPDst(vmIp.toIpPrefix());
255 - }
256 250
257 - String portName = port.annotations().value(PORT_NAME); 251 + ForwardingObjective fo = DefaultForwardingObjective.builder()
258 - if (Strings.isNullOrEmpty(portName) || 252 + .withSelector(sBuilder.build())
259 - !portName.startsWith(PORTNAME_PREFIX_VM)) { 253 + .withTreatment(DefaultTrafficTreatment.builder().build())
260 - // handles VM connected port event only 254 + .withFlag(ForwardingObjective.Flag.SPECIFIC)
261 - return; 255 + .withPriority(SWITCHING_RULE_PRIORITY)
262 - } 256 + .fromApp(appId)
257 + .remove();
263 258
264 - switch (event.type()) { 259 + flowObjectiveService.forward(deviceId, fo);
265 - case PORT_UPDATED:
266 - if (!event.port().isEnabled()) {
267 - deviceEventExecutor.execute(() -> processPortRemoved(event.port()));
268 - }
269 - break;
270 - case PORT_ADDED:
271 - deviceEventExecutor.execute(() -> processPortAdded(event.port()));
272 - break;
273 - default:
274 - break;
275 - }
276 - }
277 } 260 }
278 261
279 - private class InternalOpenstackNodeListener implements OpenstackNodeListener { 262 + @Override
280 - 263 + protected void hostDetected(Host host) {
281 - @Override 264 + populateSwitchingRules(host);
282 - public void event(OpenstackNodeEvent event) { 265 + log.info("Added new virtual machine to switching service {}", host);
283 - OpenstackNode node = event.node(); 266 + }
284 - // TODO check leadership of the node and make only the leader process 267 +
285 - 268 + @Override
286 - switch (event.type()) { 269 + protected void hostRemoved(Host host) {
287 - case COMPLETE: 270 + removeSwitchingRules(host);
288 - log.info("COMPLETE node {} detected", node.hostname()); 271 + log.info("Removed virtual machine from switching service {}", host);
289 -
290 - // adds existing VMs running on the complete state node
291 - deviceService.getPorts(node.intBridge()).stream()
292 - .filter(port -> port.annotations().value(PORT_NAME)
293 - .startsWith(PORTNAME_PREFIX_VM) &&
294 - port.isEnabled())
295 - .forEach(port -> {
296 - deviceEventExecutor.execute(() -> processPortAdded(port));
297 - log.info("VM is detected on {}", port);
298 - });
299 -
300 - // removes stale VMs
301 - hostService.getHosts().forEach(host -> {
302 - if (deviceService.getPort(host.location().deviceId(),
303 - host.location().port()) == null) {
304 - deviceEventExecutor.execute(() -> removeHosts(host.location()));
305 - log.info("Removed stale VM {}", host.location());
306 - }
307 - });
308 - break;
309 - case INCOMPLETE:
310 - log.warn("{} is changed to INCOMPLETE state", node);
311 - break;
312 - case INIT:
313 - case DEVICE_CREATED:
314 - default:
315 - break;
316 - }
317 - }
318 } 272 }
319 } 273 }
......
1 -/*
2 -* Copyright 2016-present 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.openstacknetworking.switching;
18 -
19 -import org.apache.felix.scr.annotations.Activate;
20 -import org.apache.felix.scr.annotations.Component;
21 -import org.apache.felix.scr.annotations.Deactivate;
22 -import org.apache.felix.scr.annotations.Reference;
23 -import org.apache.felix.scr.annotations.ReferenceCardinality;
24 -import org.onlab.packet.Ethernet;
25 -import org.onlab.packet.Ip4Address;
26 -import org.onlab.packet.IpAddress;
27 -import org.onosproject.net.Device;
28 -import org.onosproject.net.DeviceId;
29 -import org.onosproject.net.Host;
30 -import org.onosproject.net.PortNumber;
31 -import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
32 -import org.onosproject.net.device.DeviceService;
33 -import org.onosproject.net.flow.DefaultTrafficSelector;
34 -import org.onosproject.net.flow.DefaultTrafficTreatment;
35 -import org.onosproject.net.flow.TrafficSelector;
36 -import org.onosproject.net.flow.TrafficTreatment;
37 -import org.onosproject.net.flow.instructions.ExtensionTreatment;
38 -import org.onosproject.net.flow.instructions.ExtensionPropertyException;
39 -import org.onosproject.net.flowobjective.DefaultForwardingObjective;
40 -import org.onosproject.net.flowobjective.FlowObjectiveService;
41 -import org.onosproject.net.flowobjective.ForwardingObjective;
42 -import org.onosproject.openstacknode.OpenstackNodeService;
43 -import org.slf4j.Logger;
44 -import org.slf4j.LoggerFactory;
45 -
46 -import java.util.Objects;
47 -import java.util.Optional;
48 -
49 -import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
50 -import static org.onosproject.openstacknetworking.Constants.*;
51 -
52 -/**
53 - * Populates switching flow rules.
54 - */
55 -@Component(immediate = true)
56 -public final class OpenstackSwitchingRulePopulator extends AbstractVmHandler {
57 -
58 - private final Logger log = LoggerFactory.getLogger(getClass());
59 -
60 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
61 - protected DeviceService deviceService;
62 -
63 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 - protected FlowObjectiveService flowObjectiveService;
65 -
66 - @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 - protected OpenstackNodeService nodeService;
68 -
69 -
70 - private static final String TUNNEL_DST = "tunnelDst";
71 -
72 - @Activate
73 - protected void activate() {
74 - super.activate();
75 - }
76 -
77 - @Deactivate
78 - protected void deactivate() {
79 - super.deactivate();
80 - }
81 -
82 - private void populateSwitchingRules(Host host) {
83 - populateFlowRulesForTunnelTag(host);
84 - populateFlowRulesForTrafficToSameCnode(host);
85 - populateFlowRulesForTrafficToDifferentCnode(host);
86 -
87 - log.debug("Populated switching rule for {}", host);
88 - }
89 -
90 - private void populateFlowRulesForTunnelTag(Host host) {
91 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
92 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
93 -
94 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
95 - .matchInPort(host.location().port());
96 -
97 - tBuilder.setTunnelId(Long.valueOf(getVni(host)));
98 -
99 - ForwardingObjective fo = DefaultForwardingObjective.builder()
100 - .withSelector(sBuilder.build())
101 - .withTreatment(tBuilder.build())
102 - .withPriority(TUNNELTAG_RULE_PRIORITY)
103 - .withFlag(ForwardingObjective.Flag.SPECIFIC)
104 - .fromApp(appId)
105 - .add();
106 -
107 - flowObjectiveService.forward(host.location().deviceId(), fo);
108 - }
109 -
110 - private void populateFlowRulesForTrafficToSameCnode(Host host) {
111 - //For L2 Switching Case
112 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
113 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
114 -
115 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
116 - .matchIPDst(getIp(host).toIpPrefix())
117 - .matchTunnelId(Long.valueOf(getVni(host)));
118 -
119 - tBuilder.setOutput(host.location().port());
120 -
121 - ForwardingObjective fo = DefaultForwardingObjective.builder()
122 - .withSelector(sBuilder.build())
123 - .withTreatment(tBuilder.build())
124 - .withPriority(SWITCHING_RULE_PRIORITY)
125 - .withFlag(ForwardingObjective.Flag.SPECIFIC)
126 - .fromApp(appId)
127 - .add();
128 -
129 - flowObjectiveService.forward(host.location().deviceId(), fo);
130 - }
131 -
132 - private void populateFlowRulesForTrafficToDifferentCnode(Host host) {
133 - Ip4Address localVmIp = getIp(host);
134 - DeviceId localDeviceId = host.location().deviceId();
135 - Optional<IpAddress> localDataIp = nodeService.dataIp(localDeviceId);
136 -
137 - if (!localDataIp.isPresent()) {
138 - log.debug("Failed to get data IP for device {}",
139 - host.location().deviceId());
140 - return;
141 - }
142 -
143 - String vni = getVni(host);
144 - getVmsInDifferentCnode(host).forEach(remoteVm -> {
145 - Optional<IpAddress> remoteDataIp = nodeService.dataIp(remoteVm.location().deviceId());
146 - if (remoteDataIp.isPresent()) {
147 - setVxLanFlowRule(vni,
148 - localDeviceId,
149 - remoteDataIp.get().getIp4Address(),
150 - getIp(remoteVm));
151 -
152 - setVxLanFlowRule(vni,
153 - remoteVm.location().deviceId(),
154 - localDataIp.get().getIp4Address(),
155 - localVmIp);
156 - }
157 - });
158 - }
159 -
160 - private void setVxLanFlowRule(String vni, DeviceId deviceId, Ip4Address remoteIp,
161 - Ip4Address vmIp) {
162 - Optional<PortNumber> tunnelPort = nodeService.tunnelPort(deviceId);
163 - if (!tunnelPort.isPresent()) {
164 - log.warn("Failed to get tunnel port from {}", deviceId);
165 - return;
166 - }
167 -
168 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
169 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
170 -
171 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
172 - .matchTunnelId(Long.parseLong(vni))
173 - .matchIPDst(vmIp.toIpPrefix());
174 - tBuilder.extension(buildNiciraExtenstion(deviceId, remoteIp), deviceId)
175 - .setOutput(tunnelPort.get());
176 -
177 - ForwardingObjective fo = DefaultForwardingObjective.builder()
178 - .withSelector(sBuilder.build())
179 - .withTreatment(tBuilder.build())
180 - .withPriority(SWITCHING_RULE_PRIORITY)
181 - .withFlag(ForwardingObjective.Flag.SPECIFIC)
182 - .fromApp(appId)
183 - .add();
184 -
185 - flowObjectiveService.forward(deviceId, fo);
186 - }
187 -
188 - private void removeSwitchingRules(Host host) {
189 - removeFlowRuleForTunnelTag(host);
190 - removeFlowRuleForVMsInSameCnode(host);
191 - removeFlowRuleForVMsInDiffrentCnode(host);
192 -
193 - log.debug("Removed switching rule for {}", host);
194 - }
195 -
196 - private void removeFlowRuleForTunnelTag(Host host) {
197 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
198 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment.builder();
199 -
200 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
201 - .matchInPort(host.location().port());
202 -
203 - ForwardingObjective fo = DefaultForwardingObjective.builder()
204 - .withSelector(sBuilder.build())
205 - .withTreatment(tBuilder.build())
206 - .withPriority(TUNNELTAG_RULE_PRIORITY)
207 - .withFlag(ForwardingObjective.Flag.SPECIFIC)
208 - .fromApp(appId)
209 - .remove();
210 -
211 - flowObjectiveService.forward(host.location().deviceId(), fo);
212 - }
213 -
214 - private void removeFlowRuleForVMsInSameCnode(Host host) {
215 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
216 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
217 - .matchIPDst(getIp(host).toIpPrefix())
218 - .matchTunnelId(Long.valueOf(getVni(host)));
219 -
220 - ForwardingObjective fo = DefaultForwardingObjective.builder()
221 - .withSelector(sBuilder.build())
222 - .withTreatment(DefaultTrafficTreatment.builder().build())
223 - .withFlag(ForwardingObjective.Flag.SPECIFIC)
224 - .withPriority(SWITCHING_RULE_PRIORITY)
225 - .fromApp(appId)
226 - .remove();
227 -
228 - flowObjectiveService.forward(host.location().deviceId(), fo);
229 - }
230 -
231 - private void removeFlowRuleForVMsInDiffrentCnode(Host host) {
232 - DeviceId deviceId = host.location().deviceId();
233 - final boolean anyPortRemainedInSameCnode = hostService.getConnectedHosts(deviceId)
234 - .stream()
235 - .filter(this::isValidHost)
236 - .anyMatch(h -> Objects.equals(getVni(h), getVni(host)));
237 -
238 - getVmsInDifferentCnode(host).forEach(h -> {
239 - removeVxLanFlowRule(h.location().deviceId(), getIp(host), getVni(host));
240 - if (!anyPortRemainedInSameCnode) {
241 - removeVxLanFlowRule(deviceId, getIp(h), getVni(host));
242 - }
243 - });
244 - }
245 -
246 - private void removeVxLanFlowRule(DeviceId deviceId, Ip4Address vmIp, String vni) {
247 - TrafficSelector.Builder sBuilder = DefaultTrafficSelector.builder();
248 -
249 - sBuilder.matchEthType(Ethernet.TYPE_IPV4)
250 - .matchTunnelId(Long.valueOf(vni))
251 - .matchIPDst(vmIp.toIpPrefix());
252 -
253 - ForwardingObjective fo = DefaultForwardingObjective.builder()
254 - .withSelector(sBuilder.build())
255 - .withTreatment(DefaultTrafficTreatment.builder().build())
256 - .withFlag(ForwardingObjective.Flag.SPECIFIC)
257 - .withPriority(SWITCHING_RULE_PRIORITY)
258 - .fromApp(appId)
259 - .remove();
260 -
261 - flowObjectiveService.forward(deviceId, fo);
262 - }
263 -
264 - private ExtensionTreatment buildNiciraExtenstion(DeviceId deviceId, Ip4Address remoteIp) {
265 - Device device = deviceService.getDevice(deviceId);
266 - if (device != null && !device.is(ExtensionTreatmentResolver.class)) {
267 - log.error("The extension treatment is not supported");
268 - return null;
269 - }
270 -
271 - ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
272 - ExtensionTreatment treatment = resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
273 - try {
274 - treatment.setPropertyValue(TUNNEL_DST, remoteIp);
275 - return treatment;
276 - } catch (ExtensionPropertyException e) {
277 - log.warn("Failed to get tunnelDst extension treatment for {}", deviceId);
278 - return null;
279 - }
280 - }
281 -
282 - @Override
283 - protected void hostDetected(Host host) {
284 - populateSwitchingRules(host);
285 - log.info("Added new virtual machine to switching service {}", host);
286 - }
287 -
288 - @Override
289 - protected void hostRemoved(Host host) {
290 - removeSwitchingRules(host);
291 - log.info("Removed virtual machine from switching service {}", host);
292 - }
293 -}
...@@ -126,7 +126,7 @@ public class OpensatckRouterWebResource extends AbstractWebResource { ...@@ -126,7 +126,7 @@ public class OpensatckRouterWebResource extends AbstractWebResource {
126 126
127 OpenstackRoutingService routingService 127 OpenstackRoutingService routingService
128 = getService(OpenstackRoutingService.class); 128 = getService(OpenstackRoutingService.class);
129 - routingService.updateRouterInterface(openstackRouterInterface); 129 + routingService.addRouterInterface(openstackRouterInterface);
130 130
131 log.debug("REST API AddRouterInterface is called from router {} portId: {}, subnetId: {}, tenantId: {}", 131 log.debug("REST API AddRouterInterface is called from router {} portId: {}, subnetId: {}, tenantId: {}",
132 openstackRouterInterface.id(), openstackRouterInterface.portId(), 132 openstackRouterInterface.id(), openstackRouterInterface.portId(),
...@@ -147,7 +147,7 @@ public class OpensatckRouterWebResource extends AbstractWebResource { ...@@ -147,7 +147,7 @@ public class OpensatckRouterWebResource extends AbstractWebResource {
147 checkNotNull(id); 147 checkNotNull(id);
148 OpenstackRoutingService routingService 148 OpenstackRoutingService routingService
149 = getService(OpenstackRoutingService.class); 149 = getService(OpenstackRoutingService.class);
150 - routingService.deleteRouter(id); 150 + routingService.removeRouter(id);
151 151
152 log.debug("REST API DELETE routers is called {}", id); 152 log.debug("REST API DELETE routers is called {}", id);
153 return Response.noContent().build(); 153 return Response.noContent().build();
......
...@@ -20,7 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; ...@@ -20,7 +20,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
20 import com.fasterxml.jackson.databind.node.ObjectNode; 20 import com.fasterxml.jackson.databind.node.ObjectNode;
21 import org.onosproject.openstackinterface.OpenstackFloatingIP; 21 import org.onosproject.openstackinterface.OpenstackFloatingIP;
22 import org.onosproject.openstackinterface.web.OpenstackFloatingIpCodec; 22 import org.onosproject.openstackinterface.web.OpenstackFloatingIpCodec;
23 -import org.onosproject.openstacknetworking.OpenstackRoutingService; 23 +import org.onosproject.openstacknetworking.OpenstackFloatingIpService;
24 import org.onosproject.rest.AbstractWebResource; 24 import org.onosproject.rest.AbstractWebResource;
25 import org.slf4j.Logger; 25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory; 26 import org.slf4j.LoggerFactory;
...@@ -45,8 +45,7 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -45,8 +45,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
45 public class OpenstackFloatingIpWebResource extends AbstractWebResource { 45 public class OpenstackFloatingIpWebResource extends AbstractWebResource {
46 private final Logger log = LoggerFactory.getLogger(getClass()); 46 private final Logger log = LoggerFactory.getLogger(getClass());
47 47
48 - private static final OpenstackFloatingIpCodec FLOATING_IP_CODEC 48 + private static final OpenstackFloatingIpCodec FLOATING_IP_CODEC = new OpenstackFloatingIpCodec();
49 - = new OpenstackFloatingIpCodec();
50 49
51 /** 50 /**
52 * Create FloatingIP. 51 * Create FloatingIP.
...@@ -64,20 +63,15 @@ public class OpenstackFloatingIpWebResource extends AbstractWebResource { ...@@ -64,20 +63,15 @@ public class OpenstackFloatingIpWebResource extends AbstractWebResource {
64 ObjectMapper mapper = new ObjectMapper(); 63 ObjectMapper mapper = new ObjectMapper();
65 ObjectNode floatingIpNode = (ObjectNode) mapper.readTree(input); 64 ObjectNode floatingIpNode = (ObjectNode) mapper.readTree(input);
66 65
67 - OpenstackFloatingIP osFloatingIp = 66 + OpenstackFloatingIP osFloatingIp = FLOATING_IP_CODEC.decode(floatingIpNode, this);
68 - FLOATING_IP_CODEC.decode(floatingIpNode, this); 67 + OpenstackFloatingIpService floatingIpService =
69 - 68 + getService(OpenstackFloatingIpService.class);
70 - OpenstackRoutingService routingService = 69 + floatingIpService.createFloatingIp(osFloatingIp);
71 - getService(OpenstackRoutingService.class);
72 -
73 - routingService.createFloatingIP(osFloatingIp);
74 70
75 log.debug("REST API CREATE floatingip called"); 71 log.debug("REST API CREATE floatingip called");
76 -
77 return Response.status(Response.Status.OK).build(); 72 return Response.status(Response.Status.OK).build();
78 } catch (Exception e) { 73 } catch (Exception e) {
79 log.error("createFloatingIp failed with {}", e.toString()); 74 log.error("createFloatingIp failed with {}", e.toString());
80 -
81 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString()) 75 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
82 .build(); 76 .build();
83 } 77 }
...@@ -102,20 +96,15 @@ public class OpenstackFloatingIpWebResource extends AbstractWebResource { ...@@ -102,20 +96,15 @@ public class OpenstackFloatingIpWebResource extends AbstractWebResource {
102 ObjectMapper mapper = new ObjectMapper(); 96 ObjectMapper mapper = new ObjectMapper();
103 ObjectNode floatingIpNode = (ObjectNode) mapper.readTree(input); 97 ObjectNode floatingIpNode = (ObjectNode) mapper.readTree(input);
104 98
105 - OpenstackFloatingIP osFloatingIp = 99 + OpenstackFloatingIP osFloatingIp = FLOATING_IP_CODEC.decode(floatingIpNode, this);
106 - FLOATING_IP_CODEC.decode(floatingIpNode, this); 100 + OpenstackFloatingIpService floatingIpService =
107 - 101 + getService(OpenstackFloatingIpService.class);
108 - OpenstackRoutingService routingService = 102 + floatingIpService.updateFloatingIp(osFloatingIp);
109 - getService(OpenstackRoutingService.class);
110 -
111 - routingService.updateFloatingIP(osFloatingIp);
112 103
113 log.debug("REST API UPDATE floatingip called {}", id); 104 log.debug("REST API UPDATE floatingip called {}", id);
114 -
115 return Response.status(Response.Status.OK).build(); 105 return Response.status(Response.Status.OK).build();
116 } catch (Exception e) { 106 } catch (Exception e) {
117 log.error("updateFloatingIp failed with {}", e.toString()); 107 log.error("updateFloatingIp failed with {}", e.toString());
118 -
119 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString()) 108 return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.toString())
120 .build(); 109 .build();
121 } 110 }
...@@ -133,12 +122,11 @@ public class OpenstackFloatingIpWebResource extends AbstractWebResource { ...@@ -133,12 +122,11 @@ public class OpenstackFloatingIpWebResource extends AbstractWebResource {
133 public Response deleteFloatingIp(@PathParam("id") String id) { 122 public Response deleteFloatingIp(@PathParam("id") String id) {
134 checkNotNull(id); 123 checkNotNull(id);
135 124
136 - OpenstackRoutingService routingService = 125 + OpenstackFloatingIpService floatingIpService =
137 - getService(OpenstackRoutingService.class); 126 + getService(OpenstackFloatingIpService.class);
138 - routingService.deleteFloatingIP(id); 127 + floatingIpService.deleteFloatingIp(id);
139 128
140 log.debug("REST API DELETE floatingip is called {}", id); 129 log.debug("REST API DELETE floatingip is called {}", id);
141 -
142 return Response.noContent().build(); 130 return Response.noContent().build();
143 } 131 }
144 132
......
...@@ -79,7 +79,6 @@ public class OpenstackPortWebResource extends AbstractWebResource { ...@@ -79,7 +79,6 @@ public class OpenstackPortWebResource extends AbstractWebResource {
79 sgService.updateSecurityGroup(osPort); 79 sgService.updateSecurityGroup(osPort);
80 80
81 return Response.status(Response.Status.OK).build(); 81 return Response.status(Response.Status.OK).build();
82 -
83 } catch (IOException e) { 82 } catch (IOException e) {
84 log.error("UpdatePort post process failed due to {}", e.getMessage()); 83 log.error("UpdatePort post process failed due to {}", e.getMessage());
85 84
......
...@@ -28,6 +28,7 @@ import java.util.Optional; ...@@ -28,6 +28,7 @@ import java.util.Optional;
28 28
29 import static com.google.common.base.Preconditions.checkArgument; 29 import static com.google.common.base.Preconditions.checkArgument;
30 import static com.google.common.base.Preconditions.checkNotNull; 30 import static com.google.common.base.Preconditions.checkNotNull;
31 +import static org.onosproject.openstacknode.Constants.PATCH_INTG_BRIDGE;
31 import static org.onosproject.openstacknode.OpenstackNodeEvent.NodeState.INIT; 32 import static org.onosproject.openstacknode.OpenstackNodeEvent.NodeState.INIT;
32 33
33 /** 34 /**
...@@ -182,6 +183,20 @@ public final class OpenstackNode { ...@@ -182,6 +183,20 @@ public final class OpenstackNode {
182 return DeviceId.deviceId("ovsdb:" + managementIp.toString()); 183 return DeviceId.deviceId("ovsdb:" + managementIp.toString());
183 } 184 }
184 185
186 + /**
187 + * Returns the name of the port connected to the external network.
188 + * It returns valid value only if the node is gateway node.
189 + *
190 + * @return external port name
191 + */
192 + public Optional<String> externalPortName() {
193 + if (type == NodeType.GATEWAY) {
194 + return Optional.of(PATCH_INTG_BRIDGE);
195 + } else {
196 + return Optional.empty();
197 + }
198 + }
199 +
185 @Override 200 @Override
186 public boolean equals(Object obj) { 201 public boolean equals(Object obj) {
187 if (this == obj) { 202 if (this == obj) {
......