Hyunsun Moon
Committed by Gerrit Code Review

CORD-472 Added table 0 and physical access rules

Change-Id: I73fe01ec31cfc379b2a0c8ee99a781415fe70c5d
...@@ -426,7 +426,7 @@ public class CordVtn implements CordVtnService { ...@@ -426,7 +426,7 @@ public class CordVtn implements CordVtnService {
426 private void postInit(CordVtnNode node) { 426 private void postInit(CordVtnNode node) {
427 disconnect(node); 427 disconnect(node);
428 428
429 - ruleInstaller.init(node.intBrId(), getTunnelPort(node.intBrId())); 429 + ruleInstaller.init(node.intBrId(), node.phyPortName(), node.localIp());
430 hostService.getConnectedHosts(node.intBrId()) 430 hostService.getConnectedHosts(node.intBrId())
431 .stream() 431 .stream()
432 .forEach(vmHandler::connected); 432 .forEach(vmHandler::connected);
......
...@@ -18,11 +18,13 @@ package org.onosproject.cordvtn; ...@@ -18,11 +18,13 @@ package org.onosproject.cordvtn;
18 import com.google.common.collect.Lists; 18 import com.google.common.collect.Lists;
19 import com.google.common.collect.Maps; 19 import com.google.common.collect.Maps;
20 import org.onlab.packet.Ethernet; 20 import org.onlab.packet.Ethernet;
21 +import org.onlab.packet.IPv4;
21 import org.onlab.packet.Ip4Address; 22 import org.onlab.packet.Ip4Address;
22 import org.onlab.packet.Ip4Prefix; 23 import org.onlab.packet.Ip4Prefix;
23 import org.onlab.packet.IpAddress; 24 import org.onlab.packet.IpAddress;
24 import org.onlab.packet.IpPrefix; 25 import org.onlab.packet.IpPrefix;
25 import org.onlab.packet.MacAddress; 26 import org.onlab.packet.MacAddress;
27 +import org.onlab.packet.TpPort;
26 import org.onlab.util.ItemNotFoundException; 28 import org.onlab.util.ItemNotFoundException;
27 import org.onosproject.core.ApplicationId; 29 import org.onosproject.core.ApplicationId;
28 import org.onosproject.core.DefaultGroupId; 30 import org.onosproject.core.DefaultGroupId;
...@@ -94,15 +96,19 @@ public class CordVtnRuleInstaller { ...@@ -94,15 +96,19 @@ public class CordVtnRuleInstaller {
94 96
95 protected final Logger log = getLogger(getClass()); 97 protected final Logger log = getLogger(getClass());
96 98
97 - private static final int TABLE_IN_PORT = 0; 99 + private static final int TABLE_FIRST = 0;
98 - private static final int TABLE_ACCESS_TYPE = 1; 100 + private static final int TABLE_IN_PORT = 1;
99 - private static final int TABLE_IN_SERVICE = 2; 101 + private static final int TABLE_ACCESS_TYPE = 2;
100 - private static final int TABLE_DST_IP = 3; 102 + private static final int TABLE_IN_SERVICE = 3;
101 - private static final int TABLE_TUNNEL_IN = 4; 103 + private static final int TABLE_DST_IP = 4;
104 + private static final int TABLE_TUNNEL_IN = 5;
102 105
103 private static final int DEFAULT_PRIORITY = 5000; 106 private static final int DEFAULT_PRIORITY = 5000;
104 private static final int LOWER_PRIORITY = 4000; 107 private static final int LOWER_PRIORITY = 4000;
105 private static final int LOWEST_PRIORITY = 0; 108 private static final int LOWEST_PRIORITY = 0;
109 + private static final int HIGHER_PRIORITY = 50000;
110 +
111 + private static final int VXLAN_UDP_PORT = 4789;
106 112
107 private final ApplicationId appId; 113 private final ApplicationId appId;
108 private final FlowRuleService flowRuleService; 114 private final FlowRuleService flowRuleService;
...@@ -141,13 +147,18 @@ public class CordVtnRuleInstaller { ...@@ -141,13 +147,18 @@ public class CordVtnRuleInstaller {
141 * Installs table miss rule to a give device. 147 * Installs table miss rule to a give device.
142 * 148 *
143 * @param deviceId device id to install the rules 149 * @param deviceId device id to install the rules
144 - * @param tunnelPort tunnel port number of the device 150 + * @param phyPortName physical port name
151 + * @param localIp local data plane ip address
145 */ 152 */
146 - public void init(DeviceId deviceId, PortNumber tunnelPort) { 153 + public void init(DeviceId deviceId, String phyPortName, IpAddress localIp) {
147 // default is drop packets which can be accomplished without 154 // default is drop packets which can be accomplished without
148 // a table miss entry for all table. 155 // a table miss entry for all table.
149 - populateTunnelInPortRule(deviceId, tunnelPort); 156 + PortNumber tunnelPort = getTunnelPort(deviceId);
150 - processAccessTypeTable(deviceId); 157 + PortNumber phyPort = getPhyPort(deviceId, phyPortName);
158 +
159 + processFirstTable(deviceId, phyPort, localIp);
160 + processInPortTable(deviceId, tunnelPort, phyPort);
161 + processAccessTypeTable(deviceId, phyPort);
151 } 162 }
152 163
153 /** 164 /**
...@@ -376,109 +387,93 @@ public class CordVtnRuleInstaller { ...@@ -376,109 +387,93 @@ public class CordVtnRuleInstaller {
376 } 387 }
377 388
378 /** 389 /**
379 - * Creates a new group for a given service. 390 + * Populates default rules on the first table.
391 + * The rules are for shuttling vxlan-encapped packets and supporting physical
392 + * network connectivity.
380 * 393 *
381 - * @param deviceId device id to create a group 394 + * @param deviceId device id
382 - * @param service cord service 395 + * @param phyPort physical port number
383 - * @return group id, or null if it fails to create 396 + * @param localIp local data plane ip address
384 */ 397 */
385 - private GroupId createServiceGroup(DeviceId deviceId, CordService service) { 398 + private void processFirstTable(DeviceId deviceId, PortNumber phyPort, IpAddress localIp) {
386 - checkNotNull(service); 399 + // take vxlan packet out onto the physical port
387 - 400 + TrafficSelector selector = DefaultTrafficSelector.builder()
388 - GroupKey groupKey = getGroupKey(service.id()); 401 + .matchInPort(PortNumber.LOCAL)
389 - Group group = groupService.getGroup(deviceId, groupKey); 402 + .build();
390 - GroupId groupId = getGroupId(service.id(), deviceId);
391 -
392 - if (group != null) {
393 - log.debug("Group {} is already exist in {}", service.id(), deviceId);
394 - return groupId;
395 - }
396 -
397 - GroupBuckets buckets = getServiceGroupBuckets(deviceId, service.segmentationId(), service.hosts());
398 - GroupDescription groupDescription = new DefaultGroupDescription(
399 - deviceId,
400 - GroupDescription.Type.SELECT,
401 - buckets,
402 - groupKey,
403 - groupId.id(),
404 - appId);
405 403
406 - groupService.addGroup(groupDescription); 404 + TrafficTreatment treatment = DefaultTrafficTreatment.builder()
405 + .setOutput(phyPort)
406 + .build();
407 407
408 - return groupId; 408 + FlowRule flowRule = DefaultFlowRule.builder()
409 - } 409 + .fromApp(appId)
410 + .withSelector(selector)
411 + .withTreatment(treatment)
412 + .withPriority(HIGHER_PRIORITY)
413 + .forDevice(deviceId)
414 + .forTable(TABLE_FIRST)
415 + .makePermanent()
416 + .build();
410 417
411 - /** 418 + processFlowRule(true, flowRule);
412 - * Returns group buckets for a given device.
413 - *
414 - * @param deviceId device id
415 - * @param tunnelId tunnel id
416 - * @param hosts list of host
417 - * @return group buckets
418 - */
419 - private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId, Map<Host, IpAddress> hosts) {
420 - List<GroupBucket> buckets = Lists.newArrayList();
421 419
422 - for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) { 420 + // take a vxlan encap'd packet through the Linux stack
423 - Host host = entry.getKey(); 421 + selector = DefaultTrafficSelector.builder()
424 - Ip4Address remoteIp = entry.getValue().getIp4Address(); 422 + .matchInPort(phyPort)
425 - DeviceId hostDevice = host.location().deviceId(); 423 + .matchEthType(Ethernet.TYPE_IPV4)
424 + .matchIPProtocol(IPv4.PROTOCOL_UDP)
425 + .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
426 + .build();
426 427
427 - TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment 428 + treatment = DefaultTrafficTreatment.builder()
428 - .builder() 429 + .setOutput(PortNumber.LOCAL)
429 - .setEthDst(host.mac()); 430 + .build();
430 431
431 - if (deviceId.equals(hostDevice)) { 432 + flowRule = DefaultFlowRule.builder()
432 - tBuilder.setOutput(host.location().port()); 433 + .fromApp(appId)
433 - } else { 434 + .withSelector(selector)
434 - ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp); 435 + .withTreatment(treatment)
435 - if (tunnelDst == null) { 436 + .withPriority(HIGHER_PRIORITY)
436 - continue; 437 + .forDevice(deviceId)
437 - } 438 + .forTable(TABLE_FIRST)
439 + .makePermanent()
440 + .build();
438 441
439 - tBuilder.extension(tunnelDst, deviceId) 442 + processFlowRule(true, flowRule);
440 - .setTunnelId(tunnelId)
441 - .setOutput(getTunnelPort(hostDevice));
442 - }
443 443
444 - buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build())); 444 + // take all else to the next table
445 - } 445 + selector = DefaultTrafficSelector.builder()
446 + .build();
446 447
447 - return new GroupBuckets(buckets); 448 + treatment = DefaultTrafficTreatment.builder()
448 - } 449 + .transition(TABLE_IN_PORT)
450 + .build();
449 451
450 - /** 452 + flowRule = DefaultFlowRule.builder()
451 - * Returns globally unique group ID. 453 + .fromApp(appId)
452 - * 454 + .withSelector(selector)
453 - * @param serviceId service id 455 + .withTreatment(treatment)
454 - * @param deviceId device id 456 + .withPriority(LOWEST_PRIORITY)
455 - * @return group id 457 + .forDevice(deviceId)
456 - */ 458 + .forTable(TABLE_FIRST)
457 - private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) { 459 + .makePermanent()
458 - return new DefaultGroupId(Objects.hash(serviceId, deviceId)); 460 + .build();
459 - }
460 461
461 - /** 462 + processFlowRule(true, flowRule);
462 - * Returns group key of a service.
463 - *
464 - * @param serviceId service id
465 - * @return group key
466 - */
467 - private GroupKey getGroupKey(CordServiceId serviceId) {
468 - return new DefaultGroupKey(serviceId.id().getBytes());
469 } 463 }
470 464
471 /** 465 /**
472 - * Forward table miss rules in ACCESS_TYPE table to IN_SERVICE table. 466 + * Forward table miss packets in ACCESS_TYPE table to physical port.
473 * 467 *
474 * @param deviceId device id 468 * @param deviceId device id
469 + * @param phyPort physical port number
475 */ 470 */
476 - private void processAccessTypeTable(DeviceId deviceId) { 471 + private void processAccessTypeTable(DeviceId deviceId, PortNumber phyPort) {
477 TrafficSelector selector = DefaultTrafficSelector.builder() 472 TrafficSelector selector = DefaultTrafficSelector.builder()
478 .build(); 473 .build();
479 474
480 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 475 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
481 - .transition(TABLE_IN_SERVICE) 476 + .setOutput(phyPort)
482 .build(); 477 .build();
483 478
484 FlowRule flowRule = DefaultFlowRule.builder() 479 FlowRule flowRule = DefaultFlowRule.builder()
...@@ -495,18 +490,21 @@ public class CordVtnRuleInstaller { ...@@ -495,18 +490,21 @@ public class CordVtnRuleInstaller {
495 } 490 }
496 491
497 /** 492 /**
498 - * Populates rules for tunnel flows in port in IN_PORT table. 493 + * Populates default rules for IN_PORT table.
499 - * All flows from tunnel port are forwarded to TUNNEL_ID table. 494 + * All packets from tunnel port are forwarded to TUNNEL_ID table and all packets
495 + * from physical port to ACCESS_TYPE table.
500 * 496 *
501 * @param deviceId device id to install the rules 497 * @param deviceId device id to install the rules
502 - * @param tunnelPort tunnel port 498 + * @param tunnelPort tunnel port number
499 + * @param phyPort physical port number
503 */ 500 */
504 - private void populateTunnelInPortRule(DeviceId deviceId, PortNumber tunnelPort) { 501 + private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber phyPort) {
505 checkNotNull(tunnelPort); 502 checkNotNull(tunnelPort);
506 503
507 TrafficSelector selector = DefaultTrafficSelector.builder() 504 TrafficSelector selector = DefaultTrafficSelector.builder()
508 .matchInPort(tunnelPort) 505 .matchInPort(tunnelPort)
509 .build(); 506 .build();
507 +
510 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 508 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
511 .transition(TABLE_TUNNEL_IN) 509 .transition(TABLE_TUNNEL_IN)
512 .build(); 510 .build();
...@@ -522,6 +520,26 @@ public class CordVtnRuleInstaller { ...@@ -522,6 +520,26 @@ public class CordVtnRuleInstaller {
522 .build(); 520 .build();
523 521
524 processFlowRule(true, flowRule); 522 processFlowRule(true, flowRule);
523 +
524 + selector = DefaultTrafficSelector.builder()
525 + .matchInPort(phyPort)
526 + .build();
527 +
528 + treatment = DefaultTrafficTreatment.builder()
529 + .transition(TABLE_DST_IP)
530 + .build();
531 +
532 + flowRule = DefaultFlowRule.builder()
533 + .fromApp(appId)
534 + .withSelector(selector)
535 + .withTreatment(treatment)
536 + .withPriority(DEFAULT_PRIORITY)
537 + .forDevice(deviceId)
538 + .forTable(TABLE_IN_PORT)
539 + .makePermanent()
540 + .build();
541 +
542 + processFlowRule(true, flowRule);
525 } 543 }
526 544
527 /** 545 /**
...@@ -539,6 +557,7 @@ public class CordVtnRuleInstaller { ...@@ -539,6 +557,7 @@ public class CordVtnRuleInstaller {
539 .matchEthType(Ethernet.TYPE_IPV4) 557 .matchEthType(Ethernet.TYPE_IPV4)
540 .matchIPSrc(srcIp.toIpPrefix()) 558 .matchIPSrc(srcIp.toIpPrefix())
541 .build(); 559 .build();
560 +
542 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 561 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
543 .transition(TABLE_ACCESS_TYPE) 562 .transition(TABLE_ACCESS_TYPE)
544 .build(); 563 .build();
...@@ -559,6 +578,7 @@ public class CordVtnRuleInstaller { ...@@ -559,6 +578,7 @@ public class CordVtnRuleInstaller {
559 selector = DefaultTrafficSelector.builder() 578 selector = DefaultTrafficSelector.builder()
560 .matchInPort(inPort) 579 .matchInPort(inPort)
561 .build(); 580 .build();
581 +
562 treatment = DefaultTrafficTreatment.builder() 582 treatment = DefaultTrafficTreatment.builder()
563 .transition(TABLE_IN_SERVICE) 583 .transition(TABLE_IN_SERVICE)
564 .build(); 584 .build();
...@@ -589,6 +609,7 @@ public class CordVtnRuleInstaller { ...@@ -589,6 +609,7 @@ public class CordVtnRuleInstaller {
589 .matchIPSrc(srcRange) 609 .matchIPSrc(srcRange)
590 .matchIPDst(dstRange) 610 .matchIPDst(dstRange)
591 .build(); 611 .build();
612 +
592 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 613 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
593 .transition(TABLE_DST_IP) 614 .transition(TABLE_DST_IP)
594 .build(); 615 .build();
...@@ -666,6 +687,7 @@ public class CordVtnRuleInstaller { ...@@ -666,6 +687,7 @@ public class CordVtnRuleInstaller {
666 TrafficSelector selector = DefaultTrafficSelector.builder() 687 TrafficSelector selector = DefaultTrafficSelector.builder()
667 .matchInPort(port) 688 .matchInPort(port)
668 .build(); 689 .build();
690 +
669 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 691 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
670 .group(groupId) 692 .group(groupId)
671 .build(); 693 .build();
...@@ -701,6 +723,7 @@ public class CordVtnRuleInstaller { ...@@ -701,6 +723,7 @@ public class CordVtnRuleInstaller {
701 .matchEthType(Ethernet.TYPE_IPV4) 723 .matchEthType(Ethernet.TYPE_IPV4)
702 .matchIPDst(dstIp.toIpPrefix()) 724 .matchIPDst(dstIp.toIpPrefix())
703 .build(); 725 .build();
726 +
704 TrafficTreatment treatment = DefaultTrafficTreatment.builder() 727 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
705 .setEthDst(dstMac) 728 .setEthDst(dstMac)
706 .setOutput(inPort) 729 .setOutput(inPort)
...@@ -815,6 +838,24 @@ public class CordVtnRuleInstaller { ...@@ -815,6 +838,24 @@ public class CordVtnRuleInstaller {
815 } 838 }
816 839
817 /** 840 /**
841 + * Returns physical port name of a given device.
842 + *
843 + * @param deviceId device id
844 + * @param phyPortName physical port name
845 + * @return physical port number, or null if no physical port exists
846 + */
847 + private PortNumber getPhyPort(DeviceId deviceId, String phyPortName) {
848 + try {
849 + return deviceService.getPorts(deviceId).stream()
850 + .filter(p -> p.annotations().value("portName").contains(phyPortName) &&
851 + p.isEnabled())
852 + .findFirst().get().number();
853 + } catch (NoSuchElementException e) {
854 + return null;
855 + }
856 + }
857 +
858 + /**
818 * Returns the inport from a given flow rule if the rule contains the match of it. 859 * Returns the inport from a given flow rule if the rule contains the match of it.
819 * 860 *
820 * @param flowRule flow rule 861 * @param flowRule flow rule
...@@ -923,6 +964,99 @@ public class CordVtnRuleInstaller { ...@@ -923,6 +964,99 @@ public class CordVtnRuleInstaller {
923 } 964 }
924 965
925 /** 966 /**
967 + * Creates a new group for a given service.
968 + *
969 + * @param deviceId device id to create a group
970 + * @param service cord service
971 + * @return group id, or null if it fails to create
972 + */
973 + private GroupId createServiceGroup(DeviceId deviceId, CordService service) {
974 + checkNotNull(service);
975 +
976 + GroupKey groupKey = getGroupKey(service.id());
977 + Group group = groupService.getGroup(deviceId, groupKey);
978 + GroupId groupId = getGroupId(service.id(), deviceId);
979 +
980 + if (group != null) {
981 + log.debug("Group {} is already exist in {}", service.id(), deviceId);
982 + return groupId;
983 + }
984 +
985 + GroupBuckets buckets = getServiceGroupBuckets(deviceId, service.segmentationId(), service.hosts());
986 + GroupDescription groupDescription = new DefaultGroupDescription(
987 + deviceId,
988 + GroupDescription.Type.SELECT,
989 + buckets,
990 + groupKey,
991 + groupId.id(),
992 + appId);
993 +
994 + groupService.addGroup(groupDescription);
995 +
996 + return groupId;
997 + }
998 +
999 + /**
1000 + * Returns group buckets for a given device.
1001 + *
1002 + * @param deviceId device id
1003 + * @param tunnelId tunnel id
1004 + * @param hosts list of host
1005 + * @return group buckets
1006 + */
1007 + private GroupBuckets getServiceGroupBuckets(DeviceId deviceId, long tunnelId, Map<Host, IpAddress> hosts) {
1008 + List<GroupBucket> buckets = Lists.newArrayList();
1009 +
1010 + for (Map.Entry<Host, IpAddress> entry : hosts.entrySet()) {
1011 + Host host = entry.getKey();
1012 + Ip4Address remoteIp = entry.getValue().getIp4Address();
1013 + DeviceId hostDevice = host.location().deviceId();
1014 +
1015 + TrafficTreatment.Builder tBuilder = DefaultTrafficTreatment
1016 + .builder()
1017 + .setEthDst(host.mac());
1018 +
1019 + if (deviceId.equals(hostDevice)) {
1020 + tBuilder.setOutput(host.location().port());
1021 + } else {
1022 + ExtensionTreatment tunnelDst = getTunnelDst(deviceId, remoteIp);
1023 + if (tunnelDst == null) {
1024 + continue;
1025 + }
1026 +
1027 + tBuilder.extension(tunnelDst, deviceId)
1028 + .setTunnelId(tunnelId)
1029 + .setOutput(getTunnelPort(hostDevice));
1030 + }
1031 +
1032 + buckets.add(DefaultGroupBucket.createSelectGroupBucket(tBuilder.build()));
1033 + }
1034 +
1035 + return new GroupBuckets(buckets);
1036 + }
1037 +
1038 + /**
1039 + * Returns globally unique group ID.
1040 + *
1041 + * @param serviceId service id
1042 + * @param deviceId device id
1043 + * @return group id
1044 + */
1045 + private GroupId getGroupId(CordServiceId serviceId, DeviceId deviceId) {
1046 + return new DefaultGroupId(Objects.hash(serviceId, deviceId));
1047 + }
1048 +
1049 + /**
1050 + * Returns group key of a service.
1051 + *
1052 + * @param serviceId service id
1053 + * @return group key
1054 + */
1055 + private GroupKey getGroupKey(CordServiceId serviceId) {
1056 + return new DefaultGroupKey(serviceId.id().getBytes());
1057 + }
1058 +
1059 + /**
926 * Returns extension instruction to set tunnel destination. 1060 * Returns extension instruction to set tunnel destination.
927 * 1061 *
928 * @param deviceId device id 1062 * @param deviceId device id
......