diff --git a/NEWS b/NEWS index 8657134157d..1dfe7d14d30 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,7 @@ Post-v2.6.0 * QoS is now implemented via egress shaping rather than ingress policing. * DSCP marking is now supported, via the new northbound QoS table. * IPAM now supports fixed MAC addresses. + * Support for source IP address based routing. - Fixed regression in table stats maintenance introduced in OVS 2.3.0, wherein the number of OpenFlow table hits and misses was not accurate. diff --git a/ovn/northd/ovn-northd.c b/ovn/northd/ovn-northd.c index 91affe4c9e9..07c7b2de4c5 100644 --- a/ovn/northd/ovn-northd.c +++ b/ovn/northd/ovn-northd.c @@ -3247,10 +3247,20 @@ find_lrp_member_ip(const struct ovn_port *op, const char *ip_s) static void add_route(struct hmap *lflows, const struct ovn_port *op, const char *lrp_addr_s, const char *network_s, int plen, - const char *gateway) + const char *gateway, const char *policy) { bool is_ipv4 = strchr(network_s, '.') ? true : false; struct ds match = DS_EMPTY_INITIALIZER; + const char *dir; + uint16_t priority; + + if (policy && !strcmp(policy, "src-ip")) { + dir = "src"; + priority = plen * 2; + } else { + dir = "dst"; + priority = (plen * 2) + 1; + } /* IPv6 link-local addresses must be scoped to the local router port. */ if (!is_ipv4) { @@ -3260,7 +3270,7 @@ add_route(struct hmap *lflows, const struct ovn_port *op, ds_put_format(&match, "inport == %s && ", op->json_key); } } - ds_put_format(&match, "ip%s.dst == %s/%d", is_ipv4 ? "4" : "6", + ds_put_format(&match, "ip%s.%s == %s/%d", is_ipv4 ? "4" : "6", dir, network_s, plen); struct ds actions = DS_EMPTY_INITIALIZER; @@ -3284,7 +3294,7 @@ add_route(struct hmap *lflows, const struct ovn_port *op, /* The priority here is calculated to implement longest-prefix-match * routing. */ - ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, plen, + ovn_lflow_add(lflows, op->od, S_ROUTER_IN_IP_ROUTING, priority, ds_cstr(&match), ds_cstr(&actions)); ds_destroy(&match); ds_destroy(&actions); @@ -3397,7 +3407,9 @@ build_static_route_flow(struct hmap *lflows, struct ovn_datapath *od, goto free_prefix_s; } - add_route(lflows, out_port, lrp_addr_s, prefix_s, plen, route->nexthop); + char *policy = route->policy ? route->policy : "dst-ip"; + add_route(lflows, out_port, lrp_addr_s, prefix_s, plen, route->nexthop, + policy); free_prefix_s: free(prefix_s); @@ -4031,13 +4043,13 @@ build_lrouter_flows(struct hmap *datapaths, struct hmap *ports, for (int i = 0; i < op->lrp_networks.n_ipv4_addrs; i++) { add_route(lflows, op, op->lrp_networks.ipv4_addrs[i].addr_s, op->lrp_networks.ipv4_addrs[i].network_s, - op->lrp_networks.ipv4_addrs[i].plen, NULL); + op->lrp_networks.ipv4_addrs[i].plen, NULL, NULL); } for (int i = 0; i < op->lrp_networks.n_ipv6_addrs; i++) { add_route(lflows, op, op->lrp_networks.ipv6_addrs[i].addr_s, op->lrp_networks.ipv6_addrs[i].network_s, - op->lrp_networks.ipv6_addrs[i].plen, NULL); + op->lrp_networks.ipv6_addrs[i].plen, NULL, NULL); } } diff --git a/ovn/ovn-nb.ovsschema b/ovn/ovn-nb.ovsschema index 865dd349189..65f2d7cfe5d 100644 --- a/ovn/ovn-nb.ovsschema +++ b/ovn/ovn-nb.ovsschema @@ -1,7 +1,7 @@ { "name": "OVN_Northbound", - "version": "5.4.0", - "cksum": "4176761817 11225", + "version": "5.4.1", + "cksum": "3773248894 11490", "tables": { "NB_Global": { "columns": { @@ -196,6 +196,10 @@ "Logical_Router_Static_Route": { "columns": { "ip_prefix": {"type": "string"}, + "policy": {"type": {"key": {"type": "string", + "enum": ["set", ["src-ip", + "dst-ip"]]}, + "min": 0, "max": 1}}, "nexthop": {"type": "string"}, "output_port": {"type": {"key": "string", "min": 0, "max": 1}}}, "isRoot": false}, diff --git a/ovn/ovn-nb.xml b/ovn/ovn-nb.xml index e1b31361be6..7626551d37b 100644 --- a/ovn/ovn-nb.xml +++ b/ovn/ovn-nb.xml @@ -1083,12 +1083,40 @@ Each record represents a static route.

+

+ When multiple routes match a packet, the longest-prefix match is chosen. + For a given prefix length, a dst-ip route is preferred over + a src-ip route. +

+

IP prefix of this route (e.g. 192.168.100.0/24).

+ +

+ If it is specified, this setting describes the policy used to make + routing decisions. This setting must be one of the following strings: +

+ +

+ If not specified, the default is dst-ip. +

+
+

Nexthop IP address for this route. Nexthop IP address should be the IP diff --git a/ovn/utilities/ovn-nbctl.8.xml b/ovn/utilities/ovn-nbctl.8.xml index 2cbd6e0974a..5b702fcef7a 100644 --- a/ovn/utilities/ovn-nbctl.8.xml +++ b/ovn/utilities/ovn-nbctl.8.xml @@ -380,7 +380,7 @@

Logical Router Static Route Commands

-
[--may-exist] lr-route-add router prefix nexthop [port]
+
[--may-exist] [--policy=POLICY] lr-route-add router prefix nexthop [port]

Adds the specified route to router. @@ -395,6 +395,12 @@ on nexthop.

+

+ --policy describes the policy used to make routing + decisions. This should be one of "dst-ip" or "src-ip". If not + specified, the default is "dst-ip". +

+

It is an error if a route with prefix already exists, unless --may-exist is specified. diff --git a/ovn/utilities/ovn-nbctl.c b/ovn/utilities/ovn-nbctl.c index df1c40528ed..4df6af82782 100644 --- a/ovn/utilities/ovn-nbctl.c +++ b/ovn/utilities/ovn-nbctl.c @@ -377,7 +377,7 @@ Logical router port commands:\n\ ('enabled' or 'disabled')\n\ \n\ Route commands:\n\ - lr-route-add ROUTER PREFIX NEXTHOP [PORT]\n\ + [--policy=POLICY] lr-route-add ROUTER PREFIX NEXTHOP [PORT]\n\ add a route to ROUTER\n\ lr-route-del ROUTER [PREFIX]\n\ remove routes from ROUTER\n\ @@ -2031,6 +2031,11 @@ nbctl_lr_route_add(struct ctl_context *ctx) lr = lr_by_name_or_uuid(ctx, ctx->argv[1], true); char *prefix, *next_hop; + const char *policy = shash_find_data(&ctx->options, "--policy"); + if (policy && strcmp(policy, "src-ip") && strcmp(policy, "dst-ip")) { + ctl_fatal("bad policy: %s", policy); + } + prefix = normalize_prefix_str(ctx->argv[2]); if (!prefix) { ctl_fatal("bad prefix argument: %s", ctx->argv[2]); @@ -2091,6 +2096,9 @@ nbctl_lr_route_add(struct ctl_context *ctx) nbrec_logical_router_static_route_set_output_port(route, ctx->argv[4]); } + if (policy) { + nbrec_logical_router_static_route_set_policy(route, policy); + } free(rt_prefix); free(next_hop); free(prefix); @@ -2104,6 +2112,9 @@ nbctl_lr_route_add(struct ctl_context *ctx) if (ctx->argc == 5) { nbrec_logical_router_static_route_set_output_port(route, ctx->argv[4]); } + if (policy) { + nbrec_logical_router_static_route_set_policy(route, policy); + } nbrec_logical_router_verify_static_routes(lr); struct nbrec_logical_router_static_route **new_routes @@ -2457,7 +2468,7 @@ nbctl_lrp_get_enabled(struct ctl_context *ctx) } struct ipv4_route { - int plen; + int priority; ovs_be32 addr; const struct nbrec_logical_router_static_route *route; }; @@ -2468,8 +2479,8 @@ ipv4_route_cmp(const void *route1_, const void *route2_) const struct ipv4_route *route1p = route1_; const struct ipv4_route *route2p = route2_; - if (route1p->plen != route2p->plen) { - return route1p->plen > route2p->plen ? -1 : 1; + if (route1p->priority != route2p->priority) { + return route1p->priority > route2p->priority ? -1 : 1; } else if (route1p->addr != route2p->addr) { return ntohl(route1p->addr) < ntohl(route2p->addr) ? -1 : 1; } else { @@ -2478,7 +2489,7 @@ ipv4_route_cmp(const void *route1_, const void *route2_) } struct ipv6_route { - int plen; + int priority; struct in6_addr addr; const struct nbrec_logical_router_static_route *route; }; @@ -2489,8 +2500,8 @@ ipv6_route_cmp(const void *route1_, const void *route2_) const struct ipv6_route *route1p = route1_; const struct ipv6_route *route2p = route2_; - if (route1p->plen != route2p->plen) { - return route1p->plen > route2p->plen ? -1 : 1; + if (route1p->priority != route2p->priority) { + return route1p->priority > route2p->priority ? -1 : 1; } return memcmp(&route1p->addr, &route2p->addr, sizeof(route1p->addr)); } @@ -2505,6 +2516,12 @@ print_route(const struct nbrec_logical_router_static_route *route, struct ds *s) free(prefix); free(next_hop); + if (route->policy) { + ds_put_format(s, " %s", route->policy); + } else { + ds_put_format(s, " %s", "dst-ip"); + } + if (route->output_port) { ds_put_format(s, " %s", route->output_port); } @@ -2530,11 +2547,13 @@ nbctl_lr_route_list(struct ctl_context *ctx) = lr->static_routes[i]; unsigned int plen; ovs_be32 ipv4; + const char *policy = route->policy ? route->policy : "dst-ip"; char *error; - error = ip_parse_cidr(route->ip_prefix, &ipv4, &plen); if (!error) { - ipv4_routes[n_ipv4_routes].plen = plen; + ipv4_routes[n_ipv4_routes].priority = !strcmp(policy, "dst-ip") + ? (2 * plen) + 1 + : 2 * plen; ipv4_routes[n_ipv4_routes].addr = ipv4; ipv4_routes[n_ipv4_routes].route = route; n_ipv4_routes++; @@ -2544,7 +2563,9 @@ nbctl_lr_route_list(struct ctl_context *ctx) struct in6_addr ipv6; error = ipv6_parse_cidr(route->ip_prefix, &ipv6, &plen); if (!error) { - ipv6_routes[n_ipv6_routes].plen = plen; + ipv6_routes[n_ipv6_routes].priority = !strcmp(policy, "dst-ip") + ? (2 * plen) + 1 + : 2 * plen; ipv6_routes[n_ipv6_routes].addr = ipv6; ipv6_routes[n_ipv6_routes].route = route; n_ipv6_routes++; @@ -2947,7 +2968,7 @@ static const struct ctl_command_syntax nbctl_commands[] = { /* logical router route commands. */ { "lr-route-add", 3, 4, "ROUTER PREFIX NEXTHOP [PORT]", NULL, - nbctl_lr_route_add, NULL, "--may-exist", RW }, + nbctl_lr_route_add, NULL, "--may-exist,--policy=", RW }, { "lr-route-del", 1, 2, "ROUTER [PREFIX]", NULL, nbctl_lr_route_del, NULL, "--if-exists", RW }, { "lr-route-list", 1, 1, "ROUTER", NULL, nbctl_lr_route_list, NULL, diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at index af00dad6d6f..0ea6ab82011 100644 --- a/tests/ovn-nbctl.at +++ b/tests/ovn-nbctl.at @@ -657,20 +657,23 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1/64], [ ]) AT_CHECK([ovn-nbctl --may-exist lr-route-add lr0 10.0.0.111/24 11.0.0.1]) +AT_CHECK([ovn-nbctl --policy=src-ip lr-route-add lr0 9.16.1.0/24 11.0.0.1]) AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl IPv4 Routes - 10.0.0.0/24 11.0.0.1 - 10.0.1.0/24 11.0.1.1 lp0 - 0.0.0.0/0 192.168.0.1 + 10.0.0.0/24 11.0.0.1 dst-ip + 10.0.1.0/24 11.0.1.1 dst-ip lp0 + 9.16.1.0/24 11.0.0.1 src-ip + 0.0.0.0/0 192.168.0.1 dst-ip ]) AT_CHECK([ovn-nbctl --may-exist lr-route-add lr0 10.0.0.111/24 11.0.0.1 lp1]) AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl IPv4 Routes - 10.0.0.0/24 11.0.0.1 lp1 - 10.0.1.0/24 11.0.1.1 lp0 - 0.0.0.0/0 192.168.0.1 + 10.0.0.0/24 11.0.0.1 dst-ip lp1 + 10.0.1.0/24 11.0.1.1 dst-ip lp0 + 9.16.1.0/24 11.0.0.1 src-ip + 0.0.0.0/0 192.168.0.1 dst-ip ]) dnl Delete non-existent prefix @@ -680,11 +683,12 @@ AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.2.1/24], [1], [], AT_CHECK([ovn-nbctl --if-exists lr-route-del lr0 10.0.2.1/24]) AT_CHECK([ovn-nbctl lr-route-del lr0 10.0.1.1/24]) +AT_CHECK([ovn-nbctl lr-route-del lr0 9.16.1.0/24]) AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl IPv4 Routes - 10.0.0.0/24 11.0.0.1 lp1 - 0.0.0.0/0 192.168.0.1 + 10.0.0.0/24 11.0.0.1 dst-ip lp1 + 0.0.0.0/0 192.168.0.1 dst-ip ]) AT_CHECK([ovn-nbctl lr-route-del lr0]) @@ -698,17 +702,17 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1]) AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl IPv6 Routes - 2001:db8::/64 2001:db8:0:f102::1 lp0 - 2001:db8:1::/64 2001:db8:0:f103::1 - ::/0 2001:db8:0:f101::1 + 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip + ::/0 2001:db8:0:f101::1 dst-ip ]) AT_CHECK([ovn-nbctl lr-route-del lr0 2001:0db8:0::/64]) AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl IPv6 Routes - 2001:db8:1::/64 2001:db8:0:f103::1 - ::/0 2001:db8:0:f101::1 + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip + ::/0 2001:db8:0:f101::1 dst-ip ]) AT_CHECK([ovn-nbctl lr-route-del lr0]) @@ -725,14 +729,14 @@ AT_CHECK([ovn-nbctl lr-route-add lr0 2001:0db8:1::/64 2001:0db8:0:f103::1]) AT_CHECK([ovn-nbctl lr-route-list lr0], [0], [dnl IPv4 Routes - 10.0.0.0/24 11.0.0.1 - 10.0.1.0/24 11.0.1.1 lp0 - 0.0.0.0/0 192.168.0.1 + 10.0.0.0/24 11.0.0.1 dst-ip + 10.0.1.0/24 11.0.1.1 dst-ip lp0 + 0.0.0.0/0 192.168.0.1 dst-ip IPv6 Routes - 2001:db8::/64 2001:db8:0:f102::1 lp0 - 2001:db8:1::/64 2001:db8:0:f103::1 - ::/0 2001:db8:0:f101::1 + 2001:db8::/64 2001:db8:0:f102::1 dst-ip lp0 + 2001:db8:1::/64 2001:db8:0:f103::1 dst-ip + ::/0 2001:db8:0:f101::1 dst-ip ]) OVN_NBCTL_TEST_STOP diff --git a/tests/ovn.at b/tests/ovn.at index 4b269de1b28..6ae4247999c 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -5748,3 +5748,222 @@ OVN_CHECK_PACKETS([hv1/vm1-tx.pcap], [expected1]) OVN_CLEANUP([hv1],[hv2]) AT_CLEANUP + +AT_SETUP([ovn -- 3 HVs, 3 LRs connected via LS, source IP based routes]) +AT_SKIP_IF([test $HAVE_PYTHON = no]) +ovn_start + +# Logical network: +# Three LRs - R1, R2 and R3 that are connected to each other via LS "join" +# in 20.0.0.0/24 network. R1 has switchess foo (192.168.1.0/24) and bar +# (192.168.2.0/24) connected to it. +# +# R2 and R3 are gateway routers. +# R2 has alice (172.16.1.0/24) and R3 has bob (172.16.1.0/24) +# connected to it. Note how both alice and bob have the same subnet behind it. +# We are trying to simulate external network via those 2 switches. In real +# world the switch ports of these switches will have addresses set as "unknown" +# to make them learning switches. Or those switches will be "localnet" ones. + +# Create three hypervisors and create OVS ports corresponding to logical ports. +net_add n1 + +sim_add hv1 +as hv1 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.1 +ovs-vsctl -- add-port br-int hv1-vif1 -- \ + set interface hv1-vif1 external-ids:iface-id=foo1 \ + options:tx_pcap=hv1/vif1-tx.pcap \ + options:rxq_pcap=hv1/vif1-rx.pcap \ + ofport-request=1 + +ovs-vsctl -- add-port br-int hv1-vif2 -- \ + set interface hv1-vif2 external-ids:iface-id=bar1 \ + options:tx_pcap=hv1/vif2-tx.pcap \ + options:rxq_pcap=hv1/vif2-rx.pcap \ + ofport-request=2 + +sim_add hv2 +as hv2 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.2 +ovs-vsctl -- add-port br-int hv2-vif1 -- \ + set interface hv2-vif1 external-ids:iface-id=alice1 \ + options:tx_pcap=hv2/vif1-tx.pcap \ + options:rxq_pcap=hv2/vif1-rx.pcap \ + ofport-request=1 + +sim_add hv3 +as hv3 +ovs-vsctl add-br br-phys +ovn_attach n1 br-phys 192.168.0.3 +ovs-vsctl -- add-port br-int hv3-vif1 -- \ + set interface hv3-vif1 external-ids:iface-id=bob1 \ + options:tx_pcap=hv3/vif1-tx.pcap \ + options:rxq_pcap=hv3/vif1-rx.pcap \ + ofport-request=1 + + +ovn-nbctl create Logical_Router name=R1 +ovn-nbctl create Logical_Router name=R2 options:chassis="hv2" +ovn-nbctl create Logical_Router name=R3 options:chassis="hv3" + +ovn-nbctl ls-add foo +ovn-nbctl ls-add bar +ovn-nbctl ls-add alice +ovn-nbctl ls-add bob +ovn-nbctl ls-add join + +# Connect foo to R1 +ovn-nbctl lrp-add R1 foo 00:00:01:01:02:03 192.168.1.1/24 +ovn-nbctl lsp-add foo rp-foo -- set Logical_Switch_Port rp-foo type=router \ + options:router-port=foo addresses=\"00:00:01:01:02:03\" + +# Connect bar to R1 +ovn-nbctl lrp-add R1 bar 00:00:01:01:02:04 192.168.2.1/24 +ovn-nbctl lsp-add bar rp-bar -- set Logical_Switch_Port rp-bar type=router \ + options:router-port=bar addresses=\"00:00:01:01:02:04\" + +# Connect alice to R2 +ovn-nbctl lrp-add R2 alice 00:00:02:01:02:03 172.16.1.1/24 +ovn-nbctl lsp-add alice rp-alice -- set Logical_Switch_Port rp-alice \ + type=router options:router-port=alice addresses=\"00:00:02:01:02:03\" + +# Connect bob to R3 +ovn-nbctl lrp-add R3 bob 00:00:03:01:02:03 172.16.1.2/24 +ovn-nbctl lsp-add bob rp-bob -- set Logical_Switch_Port rp-bob \ + type=router options:router-port=bob addresses=\"00:00:03:01:02:03\" + +# Connect R1 to join +ovn-nbctl lrp-add R1 R1_join 00:00:04:01:02:03 20.0.0.1/24 +ovn-nbctl lsp-add join r1-join -- set Logical_Switch_Port r1-join \ + type=router options:router-port=R1_join addresses='"00:00:04:01:02:03"' + +# Connect R2 to join +ovn-nbctl lrp-add R2 R2_join 00:00:04:01:02:04 20.0.0.2/24 +ovn-nbctl lsp-add join r2-join -- set Logical_Switch_Port r2-join \ + type=router options:router-port=R2_join addresses='"00:00:04:01:02:04"' + +# Connect R3 to join +ovn-nbctl lrp-add R3 R3_join 00:00:04:01:02:05 20.0.0.3/24 +ovn-nbctl lsp-add join r3-join -- set Logical_Switch_Port r3-join \ + type=router options:router-port=R3_join addresses='"00:00:04:01:02:05"' + +# Install static routes with source ip address as the policy for routing. +# We want traffic from 'foo' to go via R2 and traffic of 'bar' to go via R3. +ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.1.0/24 20.0.0.2 +ovn-nbctl --policy="src-ip" lr-route-add R1 192.168.2.0/24 20.0.0.3 + +# Install static routes with destination ip address as the policy for routing. +ovn-nbctl lr-route-add R2 192.168.0.0/16 20.0.0.1 + +ovn-nbctl lr-route-add R3 192.168.0.0/16 20.0.0.1 + +# Create logical port foo1 in foo +ovn-nbctl lsp-add foo foo1 \ +-- lsp-set-addresses foo1 "f0:00:00:01:02:03 192.168.1.2" + +# Create logical port bar1 in bar +ovn-nbctl lsp-add bar bar1 \ +-- lsp-set-addresses bar1 "f0:00:00:01:02:04 192.168.2.2" + +# Create logical port alice1 in alice +ovn-nbctl lsp-add alice alice1 \ +-- lsp-set-addresses alice1 "f0:00:00:01:02:05 172.16.1.3" + +# Create logical port bob1 in bob +ovn-nbctl lsp-add bob bob1 \ +-- lsp-set-addresses bob1 "f0:00:00:01:02:06 172.16.1.4" + +# Pre-populate the hypervisors' ARP tables so that we don't lose any +# packets for ARP resolution (native tunneling doesn't queue packets +# for ARP resolution). +ovn_populate_arp + +# Allow some time for ovn-northd and ovn-controller to catch up. +# XXX This should be more systematic. +sleep 1 + +ip_to_hex() { + printf "%02x%02x%02x%02x" "$@" +} +trim_zeros() { + sed 's/\(00\)\{1,\}$//' +} + +# Send ip packets between foo1 and bar1 +# (East-west traffic should flow normally) +src_mac="f00000010203" +dst_mac="000001010203" +src_ip=`ip_to_hex 192 168 1 2` +dst_ip=`ip_to_hex 192 168 2 2` +packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 +as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet + +# Send ip packets between foo1 and alice1 +src_mac="f00000010203" +dst_mac="000001010203" +src_ip=`ip_to_hex 192 168 1 2` +dst_ip=`ip_to_hex 172 16 1 3` +packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 +as hv1 ovs-appctl netdev-dummy/receive hv1-vif1 $packet +#as hv1 ovs-appctl ofproto/trace br-int in_port=1 $packet + +# Send ip packets between bar1 and bob1 +src_mac="f00000010204" +dst_mac="000001010204" +src_ip=`ip_to_hex 192 168 2 2` +dst_ip=`ip_to_hex 172 16 1 4` +packet=${dst_mac}${src_mac}08004500001c0000000040110000${src_ip}${dst_ip}0035111100080000 +as hv1 ovs-appctl netdev-dummy/receive hv1-vif2 $packet +#as hv1 ovs-appctl ofproto/trace br-int in_port=2 $packet + +# Packet to expect at bar1 +src_mac="000001010204" +dst_mac="f00000010204" +src_ip=`ip_to_hex 192 168 1 2` +dst_ip=`ip_to_hex 192 168 2 2` +expected=${dst_mac}${src_mac}08004500001c000000003f110100${src_ip}${dst_ip}0035111100080000 +echo $expected > expected +OVN_CHECK_PACKETS([hv1/vif2-tx.pcap], [expected]) + +# Packet to Expect at alice1 +src_mac="000002010203" +dst_mac="f00000010205" +src_ip=`ip_to_hex 192 168 1 2` +dst_ip=`ip_to_hex 172 16 1 3` +expected=${dst_mac}${src_mac}08004500001c000000003e110200${src_ip}${dst_ip}0035111100080000 +echo $expected > expected +OVN_CHECK_PACKETS([hv2/vif1-tx.pcap], [expected]) + +# Packet to Expect at bob1 +src_mac="000003010203" +dst_mac="f00000010206" +src_ip=`ip_to_hex 192 168 2 2` +dst_ip=`ip_to_hex 172 16 1 4` +expected=${dst_mac}${src_mac}08004500001c000000003e110200${src_ip}${dst_ip}0035111100080000 +echo $expected > expected +OVN_CHECK_PACKETS([hv3/vif1-tx.pcap], [expected]) + +for sim in hv1 hv2 hv3; do + as $sim + OVS_APP_EXIT_AND_WAIT([ovn-controller]) + OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) + OVS_APP_EXIT_AND_WAIT([ovsdb-server]) +done + +as ovn-sb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as ovn-nb +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +as northd +OVS_APP_EXIT_AND_WAIT([ovn-northd]) + +as main +OVS_APP_EXIT_AND_WAIT([ovs-vswitchd]) +OVS_APP_EXIT_AND_WAIT([ovsdb-server]) + +AT_CLEANUP