return rsp;
}
- // This is for Logical SFFs
public Optional<String> getFirstHopSfInterfaceFromRsp(RenderedServicePath rsp) {
- Optional<RenderedServicePathHop> firstHop = getRspFirstHop(rsp);
- if (!firstHop.isPresent()) {
- LOG.warn("getFirstHopSfInterfaceFromRsp RSP [{}] cant get first hop", rsp.getName().getValue());
- return Optional.empty();
- }
+ return getRspFirstHop(rsp).flatMap(this::getHopSfInterface);
+ }
+
+ public Optional<String> getLastHopSfInterfaceFromRsp(RenderedServicePath rsp) {
+ return getRspLastHop(rsp).flatMap(this::getHopSfInterface);
+ }
+
+ public Optional<String> getHopSfInterface(RenderedServicePathHop hop) {
+
+ LOG.trace("getHopSfInterface of hop {}", hop);
- SfName sfName = firstHop.get().getServiceFunctionName();
+ SfName sfName = hop.getServiceFunctionName();
if (sfName == null) {
- LOG.warn("getFirstHopSfInterfaceFromRsp RSP [{}] first hop has no SF", rsp.getName().getValue());
+ LOG.warn("getHopSfInterface hop has no SF");
return Optional.empty();
}
Optional<ServiceFunction> sf = getServiceFunction(sfName);
if (!sf.isPresent()) {
- LOG.warn("getFirstHopSfInterfaceFromRsp RSP [{}] SF [{}] does not exist", rsp.getName().getValue(),
- sfName.getValue());
+ LOG.warn("getHopSfInterface SF [{}] does not exist", sfName.getValue());
return Optional.empty();
}
List<SfDataPlaneLocator> sfDplList = sf.get().getSfDataPlaneLocator();
if (sfDplList == null || sfDplList.isEmpty()) {
- LOG.warn("getFirstHopSfInterfaceFromRsp RSP [{}] SF [{}] has no SfDpl", rsp.getName().getValue(),
- sfName.getValue());
+ LOG.warn("getHopSfInterface SF [{}] has no SfDpl", sfName.getValue());
return Optional.empty();
}
return Optional.ofNullable(hops.get(0));
}
+
+ private Optional<RenderedServicePathHop> getRspLastHop(RenderedServicePath rsp) {
+ List<RenderedServicePathHop> hops = rsp.getRenderedServicePathHop();
+ if (hops == null || hops.isEmpty()) {
+ LOG.warn("getRspLastHop RSP [{}] has no hops list", rsp.getName().getValue());
+ return Optional.empty();
+ }
+
+ return Optional.ofNullable(hops.get(hops.size() - 1));
+ }
}
return Collections.emptySet();
}
+ String lastHopInterface = sfcProvider.getLastHopSfInterfaceFromRsp(rsp).orElse(null);
+ if (lastHopInterface == null) {
+ LOG.error("RSP has no valid last hop interface");
+ return Collections.emptySet();
+ }
+
+ DpnIdType lastHopDpn = geniusProvider.getDpnIdFromInterfaceName(lastHopInterface).orElse(null);
+ if (lastHopDpn == null) {
+ LOG.error("RSP has no valid last hop DPN");
+ return Collections.emptySet();
+ }
+
List<String> interfaces = new ArrayList<>();
NeutronNetwork network = matches.getAugmentation(NeutronNetwork.class);
if (network != null) {
nsi));
});
+ // To handle chain egress when origin, last SF and destination are on the same node,
+ // we need to bind to the SF interface so that SFC pipeline to classifier pipeline
+ // hand-off can happen through the dispatcher table
+ if (nodeDpn.equals(lastHopDpn)) {
+ entries.add(ClassifierEntry.buildIngressEntry(new InterfaceKey(lastHopInterface)));
+ }
+
// Egress services must bind to egress ports. Since we dont know before-hand what
// the egress ports will be, we will bind on all switch ports. If the packet
// doesnt have NSH, it will be returned to the the egress dispatcher table.