Charles Chan
Committed by Gerrit Code Review

CORD-546 Push L3 unicast rules for bgp peers when they are learned

- Change L3 unicast group id/key generation to include src MAC
- Note: Only flows are removed when a peer is gone
  since the group may still be referenced by routes announced by peer.
  It does no harm even if the group is not referenced.
- Note: We assume that peer does not move or update IP

Also fix several SR/VR integration issues, including
- Do not push broadcast group for /32

Change-Id: Ifb03601f5341f8b7717ea1fbccbc569b07f66476
...@@ -16,19 +16,25 @@ ...@@ -16,19 +16,25 @@
16 16
17 package org.onosproject.routing.impl; 17 package org.onosproject.routing.impl;
18 18
19 +import com.google.common.collect.ImmutableSortedSet;
20 +import com.google.common.collect.Maps;
19 import org.apache.felix.scr.annotations.Activate; 21 import org.apache.felix.scr.annotations.Activate;
20 import org.apache.felix.scr.annotations.Component; 22 import org.apache.felix.scr.annotations.Component;
21 import org.apache.felix.scr.annotations.Deactivate; 23 import org.apache.felix.scr.annotations.Deactivate;
22 import org.apache.felix.scr.annotations.Reference; 24 import org.apache.felix.scr.annotations.Reference;
23 import org.apache.felix.scr.annotations.ReferenceCardinality; 25 import org.apache.felix.scr.annotations.ReferenceCardinality;
24 import org.onlab.packet.EthType; 26 import org.onlab.packet.EthType;
27 +import org.onlab.packet.IpPrefix;
28 +import org.onlab.packet.MacAddress;
25 import org.onlab.packet.VlanId; 29 import org.onlab.packet.VlanId;
26 import org.onosproject.core.ApplicationId; 30 import org.onosproject.core.ApplicationId;
27 import org.onosproject.core.CoreService; 31 import org.onosproject.core.CoreService;
28 import org.onosproject.incubator.net.intf.Interface; 32 import org.onosproject.incubator.net.intf.Interface;
29 import org.onosproject.incubator.net.intf.InterfaceService; 33 import org.onosproject.incubator.net.intf.InterfaceService;
34 +import org.onosproject.mastership.MastershipService;
30 import org.onosproject.net.ConnectPoint; 35 import org.onosproject.net.ConnectPoint;
31 import org.onosproject.net.DeviceId; 36 import org.onosproject.net.DeviceId;
37 +import org.onosproject.net.Host;
32 import org.onosproject.net.PortNumber; 38 import org.onosproject.net.PortNumber;
33 import org.onosproject.net.config.NetworkConfigEvent; 39 import org.onosproject.net.config.NetworkConfigEvent;
34 import org.onosproject.net.config.NetworkConfigListener; 40 import org.onosproject.net.config.NetworkConfigListener;
...@@ -45,15 +51,23 @@ import org.onosproject.net.flowobjective.DefaultNextObjective; ...@@ -45,15 +51,23 @@ import org.onosproject.net.flowobjective.DefaultNextObjective;
45 import org.onosproject.net.flowobjective.FlowObjectiveService; 51 import org.onosproject.net.flowobjective.FlowObjectiveService;
46 import org.onosproject.net.flowobjective.ForwardingObjective; 52 import org.onosproject.net.flowobjective.ForwardingObjective;
47 import org.onosproject.net.flowobjective.NextObjective; 53 import org.onosproject.net.flowobjective.NextObjective;
54 +import org.onosproject.net.host.HostEvent;
55 +import org.onosproject.net.host.HostListener;
56 +import org.onosproject.net.host.HostService;
48 import org.onosproject.net.host.InterfaceIpAddress; 57 import org.onosproject.net.host.InterfaceIpAddress;
49 import org.onosproject.routing.RoutingService; 58 import org.onosproject.routing.RoutingService;
50 import org.onosproject.routing.config.RouterConfig; 59 import org.onosproject.routing.config.RouterConfig;
51 import org.slf4j.Logger; 60 import org.slf4j.Logger;
52 61
53 import java.util.Collections; 62 import java.util.Collections;
63 +import java.util.Iterator;
54 import java.util.List; 64 import java.util.List;
65 +import java.util.Map;
66 +import java.util.Optional;
67 +import java.util.Set;
55 68
56 import static org.slf4j.LoggerFactory.getLogger; 69 import static org.slf4j.LoggerFactory.getLogger;
70 +import static com.google.common.base.Preconditions.checkState;
57 71
58 /** 72 /**
59 * Manages connectivity between peers redirecting control traffic to a routing 73 * Manages connectivity between peers redirecting control traffic to a routing
...@@ -64,7 +78,8 @@ public class ControlPlaneRedirectManager { ...@@ -64,7 +78,8 @@ public class ControlPlaneRedirectManager {
64 78
65 private final Logger log = getLogger(getClass()); 79 private final Logger log = getLogger(getClass());
66 80
67 - private static final int PRIORITY = 40001; 81 + private static final int MIN_IP_PRIORITY = 10;
82 + private static final int ACL_PRIORITY = 40001;
68 private static final int OSPF_IP_PROTO = 0x59; 83 private static final int OSPF_IP_PROTO = 0x59;
69 84
70 private static final String APP_NAME = "org.onosproject.cpredirect"; 85 private static final String APP_NAME = "org.onosproject.cpredirect";
...@@ -73,6 +88,7 @@ public class ControlPlaneRedirectManager { ...@@ -73,6 +88,7 @@ public class ControlPlaneRedirectManager {
73 private ConnectPoint controlPlaneConnectPoint; 88 private ConnectPoint controlPlaneConnectPoint;
74 private boolean ospfEnabled = false; 89 private boolean ospfEnabled = false;
75 private List<String> interfaces = Collections.emptyList(); 90 private List<String> interfaces = Collections.emptyList();
91 + private Map<Host, Set<Integer>> peerNextId = Maps.newConcurrentMap();
76 92
77 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected CoreService coreService; 94 protected CoreService coreService;
...@@ -89,9 +105,16 @@ public class ControlPlaneRedirectManager { ...@@ -89,9 +105,16 @@ public class ControlPlaneRedirectManager {
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY) 105 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected NetworkConfigService networkConfigService; 106 protected NetworkConfigService networkConfigService;
91 107
108 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
109 + protected MastershipService mastershipService;
110 +
111 + @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 + protected HostService hostService;
113 +
92 private final InternalDeviceListener deviceListener = new InternalDeviceListener(); 114 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
93 private final InternalNetworkConfigListener networkConfigListener = 115 private final InternalNetworkConfigListener networkConfigListener =
94 new InternalNetworkConfigListener(); 116 new InternalNetworkConfigListener();
117 + private final InternalHostListener hostListener = new InternalHostListener();
95 118
96 @Activate 119 @Activate
97 public void activate() { 120 public void activate() {
...@@ -99,6 +122,7 @@ public class ControlPlaneRedirectManager { ...@@ -99,6 +122,7 @@ public class ControlPlaneRedirectManager {
99 122
100 deviceService.addListener(deviceListener); 123 deviceService.addListener(deviceListener);
101 networkConfigService.addListener(networkConfigListener); 124 networkConfigService.addListener(networkConfigListener);
125 + hostService.addListener(hostListener);
102 126
103 updateConfig(); 127 updateConfig();
104 } 128 }
...@@ -107,6 +131,7 @@ public class ControlPlaneRedirectManager { ...@@ -107,6 +131,7 @@ public class ControlPlaneRedirectManager {
107 public void deactivate() { 131 public void deactivate() {
108 deviceService.removeListener(deviceListener); 132 deviceService.removeListener(deviceListener);
109 networkConfigService.removeListener(networkConfigListener); 133 networkConfigService.removeListener(networkConfigListener);
134 + hostService.removeListener(hostListener);
110 } 135 }
111 136
112 private void updateConfig() { 137 private void updateConfig() {
...@@ -309,7 +334,7 @@ public class ControlPlaneRedirectManager { ...@@ -309,7 +334,7 @@ public class ControlPlaneRedirectManager {
309 fobBuilder.nextStep(nextId); 334 fobBuilder.nextStep(nextId);
310 } 335 }
311 fobBuilder.fromApp(appId) 336 fobBuilder.fromApp(appId)
312 - .withPriority(PRIORITY) 337 + .withPriority(ACL_PRIORITY)
313 .withFlag(ForwardingObjective.Flag.VERSATILE); 338 .withFlag(ForwardingObjective.Flag.VERSATILE);
314 339
315 return add ? fobBuilder.add() : fobBuilder.remove(); 340 return add ? fobBuilder.add() : fobBuilder.remove();
...@@ -366,4 +391,149 @@ public class ControlPlaneRedirectManager { ...@@ -366,4 +391,149 @@ public class ControlPlaneRedirectManager {
366 } 391 }
367 } 392 }
368 } 393 }
394 +
395 + /**
396 + * Listener for host events.
397 + */
398 + private class InternalHostListener implements HostListener {
399 + private void peerAdded(HostEvent event) {
400 + Host peer = event.subject();
401 + Optional<Interface> peerIntf =
402 + interfaceService.getInterfacesByPort(peer.location()).stream()
403 + .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
404 + .filter(intf -> peer.vlan().equals(intf.vlan()))
405 + .findFirst();
406 + if (!peerIntf.isPresent()) {
407 + log.debug("Adding peer {}/{} on {} but the interface is not configured",
408 + peer.mac(), peer.vlan(), peer.location());
409 + return;
410 + }
411 +
412 + // Generate L3 Unicast groups and store it in the map
413 + int toRouterL3Unicast = createPeerGroup(peer.mac(), peerIntf.get().mac(),
414 + peer.vlan(), peer.location().deviceId(), controlPlaneConnectPoint.port());
415 + int toPeerL3Unicast = createPeerGroup(peerIntf.get().mac(), peer.mac(),
416 + peer.vlan(), peer.location().deviceId(), peer.location().port());
417 + peerNextId.put(peer, ImmutableSortedSet.of(toRouterL3Unicast, toPeerL3Unicast));
418 +
419 + // From peer to router
420 + peerIntf.get().ipAddresses().forEach(routerIp -> {
421 + flowObjectiveService.forward(peer.location().deviceId(),
422 + createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).add());
423 + });
424 +
425 + // From router to peer
426 + peer.ipAddresses().forEach(peerIp -> {
427 + flowObjectiveService.forward(peer.location().deviceId(),
428 + createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).add());
429 + });
430 + }
431 +
432 + private void peerRemoved(HostEvent event) {
433 + Host peer = event.subject();
434 + Optional<Interface> peerIntf =
435 + interfaceService.getInterfacesByPort(peer.location()).stream()
436 + .filter(intf -> interfaces.isEmpty() || interfaces.contains(intf.name()))
437 + .filter(intf -> peer.vlan().equals(intf.vlan()))
438 + .findFirst();
439 + if (!peerIntf.isPresent()) {
440 + log.debug("Removing peer {}/{} on {} but the interface is not configured",
441 + peer.mac(), peer.vlan(), peer.location());
442 + return;
443 + }
444 +
445 + Set<Integer> nextIds = peerNextId.get(peer);
446 + checkState(peerNextId.get(peer) != null,
447 + "Peer nextId should not be null");
448 + checkState(peerNextId.get(peer).size() == 2,
449 + "Wrong nextId associated with the peer");
450 + Iterator<Integer> iter = peerNextId.get(peer).iterator();
451 + int toRouterL3Unicast = iter.next();
452 + int toPeerL3Unicast = iter.next();
453 +
454 + // From peer to router
455 + peerIntf.get().ipAddresses().forEach(routerIp -> {
456 + flowObjectiveService.forward(peer.location().deviceId(),
457 + createPeerObjBuilder(toRouterL3Unicast, routerIp.ipAddress().toIpPrefix()).remove());
458 + });
459 +
460 + // From router to peer
461 + peer.ipAddresses().forEach(peerIp -> {
462 + flowObjectiveService.forward(peer.location().deviceId(),
463 + createPeerObjBuilder(toPeerL3Unicast, peerIp.toIpPrefix()).remove());
464 + });
465 + }
466 +
467 + private ForwardingObjective.Builder createPeerObjBuilder(
468 + int nextId, IpPrefix ipAddresses) {
469 + TrafficSelector.Builder sbuilder = DefaultTrafficSelector.builder();
470 + sbuilder.matchEthType(EthType.EtherType.IPV4.ethType().toShort());
471 + sbuilder.matchIPDst(ipAddresses);
472 + DefaultForwardingObjective.Builder builder =
473 + DefaultForwardingObjective.builder()
474 + .withSelector(sbuilder.build())
475 + .fromApp(appId)
476 + .withPriority(getPriorityFromPrefix(ipAddresses))
477 + .withFlag(ForwardingObjective.Flag.SPECIFIC);
478 + if (nextId != -1) {
479 + builder.nextStep(nextId);
480 + }
481 + return builder;
482 + }
483 +
484 + private int createPeerGroup(MacAddress srcMac, MacAddress dstMac,
485 + VlanId vlanId, DeviceId deviceId, PortNumber port) {
486 + int nextId = flowObjectiveService.allocateNextId();
487 + NextObjective.Builder nextObjBuilder = DefaultNextObjective.builder()
488 + .withId(nextId)
489 + .withType(NextObjective.Type.SIMPLE)
490 + .fromApp(appId);
491 +
492 + TrafficTreatment.Builder ttBuilder = DefaultTrafficTreatment.builder();
493 + ttBuilder.setEthSrc(srcMac);
494 + ttBuilder.setEthDst(dstMac);
495 + ttBuilder.setOutput(port);
496 + nextObjBuilder.addTreatment(ttBuilder.build());
497 +
498 + TrafficSelector.Builder metabuilder = DefaultTrafficSelector.builder();
499 + VlanId matchVlanId = (vlanId.equals(VlanId.NONE)) ?
500 + VlanId.vlanId(SingleSwitchFibInstaller.ASSIGNED_VLAN) :
501 + vlanId;
502 + metabuilder.matchVlanId(matchVlanId);
503 + nextObjBuilder.withMeta(metabuilder.build());
504 +
505 + flowObjectiveService.next(deviceId, nextObjBuilder.add());
506 + return nextId;
507 + }
508 +
509 + @Override
510 + public void event(HostEvent event) {
511 + DeviceId deviceId = event.subject().location().deviceId();
512 + if (!mastershipService.isLocalMaster(deviceId)) {
513 + return;
514 + }
515 + switch (event.type()) {
516 + case HOST_ADDED:
517 + peerAdded(event);
518 + break;
519 + case HOST_MOVED:
520 + //TODO We assume BGP peer does not move for now
521 + break;
522 + case HOST_REMOVED:
523 + peerRemoved(event);
524 + break;
525 + case HOST_UPDATED:
526 + //TODO We assume BGP peer does not change IP for now
527 + break;
528 + default:
529 + break;
530 + }
531 + }
532 + }
533 +
534 + private int getPriorityFromPrefix(IpPrefix prefix) {
535 + return (prefix.isIp4()) ?
536 + 2000 * prefix.prefixLength() + MIN_IP_PRIORITY :
537 + 500 * prefix.prefixLength() + MIN_IP_PRIORITY;
538 + }
369 } 539 }
......
...@@ -558,12 +558,16 @@ public class RoutingRulePopulator { ...@@ -558,12 +558,16 @@ public class RoutingRulePopulator {
558 */ 558 */
559 public void populateSubnetBroadcastRule(DeviceId deviceId) { 559 public void populateSubnetBroadcastRule(DeviceId deviceId) {
560 config.getSubnets(deviceId).forEach(subnet -> { 560 config.getSubnets(deviceId).forEach(subnet -> {
561 + if (subnet.prefixLength() == 0 ||
562 + subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH) {
563 + return;
564 + }
561 int nextId = srManager.getSubnetNextObjectiveId(deviceId, subnet); 565 int nextId = srManager.getSubnetNextObjectiveId(deviceId, subnet);
562 VlanId vlanId = srManager.getSubnetAssignedVlanId(deviceId, subnet); 566 VlanId vlanId = srManager.getSubnetAssignedVlanId(deviceId, subnet);
563 567
564 if (nextId < 0 || vlanId == null) { 568 if (nextId < 0 || vlanId == null) {
565 - log.error("Cannot install subnet broadcast rule in dev:{} due" 569 + log.error("Cannot install subnet {} broadcast rule in dev:{} due"
566 - + "to vlanId:{} or nextId:{}", vlanId, nextId); 570 + + "to vlanId:{} or nextId:{}", subnet, deviceId, vlanId, nextId);
567 return; 571 return;
568 } 572 }
569 573
......
...@@ -278,6 +278,10 @@ public class DeviceConfiguration implements DeviceProperties { ...@@ -278,6 +278,10 @@ public class DeviceConfiguration implements DeviceProperties {
278 PortNumber port = entry.getKey(); 278 PortNumber port = entry.getKey();
279 Ip4Prefix subnet = entry.getValue(); 279 Ip4Prefix subnet = entry.getValue();
280 280
281 + if (subnet.prefixLength() == IpPrefix.MAX_INET_MASK_LENGTH) {
282 + return;
283 + }
284 +
281 if (subnetPortMap.containsKey(subnet)) { 285 if (subnetPortMap.containsKey(subnet)) {
282 subnetPortMap.get(subnet).add(port); 286 subnetPortMap.get(subnet).add(port);
283 } else { 287 } else {
......
1 package org.onosproject.driver.pipeline; 1 package org.onosproject.driver.pipeline;
2 2
3 -import com.google.common.base.Objects;
4 import com.google.common.cache.Cache; 3 import com.google.common.cache.Cache;
5 import com.google.common.cache.CacheBuilder; 4 import com.google.common.cache.CacheBuilder;
6 import com.google.common.cache.RemovalCause; 5 import com.google.common.cache.RemovalCause;
...@@ -46,6 +45,7 @@ import java.util.Collections; ...@@ -46,6 +45,7 @@ import java.util.Collections;
46 import java.util.Deque; 45 import java.util.Deque;
47 import java.util.List; 46 import java.util.List;
48 import java.util.Map; 47 import java.util.Map;
48 +import java.util.Objects;
49 import java.util.Set; 49 import java.util.Set;
50 import java.util.concurrent.ConcurrentHashMap; 50 import java.util.concurrent.ConcurrentHashMap;
51 import java.util.concurrent.CopyOnWriteArrayList; 51 import java.util.concurrent.CopyOnWriteArrayList;
...@@ -333,6 +333,7 @@ public class OFDPA2GroupHandler { ...@@ -333,6 +333,7 @@ public class OFDPA2GroupHandler {
333 VlanId vlanid = null; 333 VlanId vlanid = null;
334 long portNum = 0; 334 long portNum = 0;
335 boolean setVlan = false, popVlan = false; 335 boolean setVlan = false, popVlan = false;
336 + MacAddress srcMac = MacAddress.ZERO;
336 MacAddress dstMac = MacAddress.ZERO; 337 MacAddress dstMac = MacAddress.ZERO;
337 for (Instruction ins : treatment.allInstructions()) { 338 for (Instruction ins : treatment.allInstructions()) {
338 if (ins.type() == Instruction.Type.L2MODIFICATION) { 339 if (ins.type() == Instruction.Type.L2MODIFICATION) {
...@@ -343,7 +344,8 @@ public class OFDPA2GroupHandler { ...@@ -343,7 +344,8 @@ public class OFDPA2GroupHandler {
343 outerTtb.setEthDst(dstMac); 344 outerTtb.setEthDst(dstMac);
344 break; 345 break;
345 case ETH_SRC: 346 case ETH_SRC:
346 - outerTtb.setEthSrc(((L2ModificationInstruction.ModEtherInstruction) l2ins).mac()); 347 + srcMac = ((L2ModificationInstruction.ModEtherInstruction) l2ins).mac();
348 + outerTtb.setEthSrc(srcMac);
347 break; 349 break;
348 case VLAN_ID: 350 case VLAN_ID:
349 vlanid = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId(); 351 vlanid = ((L2ModificationInstruction.ModVlanIdInstruction) l2ins).vlanId();
...@@ -433,11 +435,10 @@ public class OFDPA2GroupHandler { ...@@ -433,11 +435,10 @@ public class OFDPA2GroupHandler {
433 mplsgroupkey, nextId); 435 mplsgroupkey, nextId);
434 } else { 436 } else {
435 // outer group is L3Unicast 437 // outer group is L3Unicast
436 - int l3groupId = L3_UNICAST_TYPE | 438 + int l3GroupIdHash = Objects.hash(srcMac, dstMac, portNum);
437 - (TYPE_MASK & (int) (dstMac.toLong() & 0xffff) << 6 | (int) portNum); 439 + int l3groupId = L3_UNICAST_TYPE | (TYPE_MASK & l3GroupIdHash);
438 - int l3gk = L3_UNICAST_TYPE | 440 + int l3GroupKeyHash = Objects.hash(deviceId, srcMac, dstMac, portNum);
439 - (TYPE_MASK & (deviceId.hashCode() << 22 | 441 + int l3gk = L3_UNICAST_TYPE | (TYPE_MASK & l3GroupKeyHash);
440 - (int) (dstMac.toLong() & 0xffff) << 6 | (int) portNum));
441 final GroupKey l3groupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3gk)); 442 final GroupKey l3groupkey = new DefaultGroupKey(OFDPA2Pipeline.appKryo.serialize(l3gk));
442 outerTtb.group(new DefaultGroupId(l2groupId)); 443 outerTtb.group(new DefaultGroupId(l2groupId));
443 // create the l3unicast group description to wait for the 444 // create the l3unicast group description to wait for the
...@@ -1059,7 +1060,7 @@ public class OFDPA2GroupHandler { ...@@ -1059,7 +1060,7 @@ public class OFDPA2GroupHandler {
1059 DeviceId deviceId, VlanId vlanId, long portNumber) { 1060 DeviceId deviceId, VlanId vlanId, long portNumber) {
1060 int portLowerBits = (int) portNumber & PORT_LOWER_BITS_MASK; 1061 int portLowerBits = (int) portNumber & PORT_LOWER_BITS_MASK;
1061 long portHigherBits = portNumber & PORT_HIGHER_BITS_MASK; 1062 long portHigherBits = portNumber & PORT_HIGHER_BITS_MASK;
1062 - int hash = Objects.hashCode(deviceId, vlanId, portHigherBits); 1063 + int hash = Objects.hash(deviceId, vlanId, portHigherBits);
1063 return L2_INTERFACE_TYPE | (TYPE_MASK & hash << 6) | portLowerBits; 1064 return L2_INTERFACE_TYPE | (TYPE_MASK & hash << 6) | portLowerBits;
1064 } 1065 }
1065 1066
......