+ }
+
/* This is a catch-all rule. It has the lowest priority (0)
* does a match-all("1") and pass-through (next) */
ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY, 0, "1",
REG_ECMP_GROUP_ID" = 0; next;",
lflow_ref);
+ ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY_PRE, 0, "1",
+ REG_POLICY_CHAIN_ID" = 0; next;",
+ lflow_ref);
ovn_lflow_add(lflows, od, S_ROUTER_IN_POLICY_ECMP, 150,
REG_ECMP_GROUP_ID" == 0", "next;",
lflow_ref);
@@ -14163,7 +14227,7 @@ build_ingress_policy_flows_for_lrouter(
/* Convert routing policies to flows. */
uint16_t ecmp_group_id = 1;
- struct route_policy *rp;
+
HMAP_FOR_EACH_WITH_HASH (rp, key_node, uuid_hash(&od->key),
route_policies) {
const struct nbrec_logical_router_policy *rule = rp->rule;
@@ -14176,9 +14240,12 @@ build_ingress_policy_flows_for_lrouter(
ecmp_group_id++;
} else {
build_routing_policy_flow(lflows, od, lr_ports, rp,
- &rule->header_, lflow_ref);
+ &rule->header_, lflow_ref,
+ &chain_ids);
}
}
+
+ simap_destroy(&chain_ids);
}
/* Local router ingress table ARP_RESOLVE: ARP Resolution. */
diff --git a/northd/northd.h b/northd/northd.h
index 9457a7be6..364f8f3e6 100644
--- a/northd/northd.h
+++ b/northd/northd.h
@@ -491,17 +491,18 @@ enum ovn_stage {
PIPELINE_STAGE(ROUTER, IN, IP_ROUTING_PRE, 13,
"lr_in_ip_routing_pre") \
PIPELINE_STAGE(ROUTER, IN, IP_ROUTING, 14,
"lr_in_ip_routing") \
PIPELINE_STAGE(ROUTER, IN, IP_ROUTING_ECMP, 15,
"lr_in_ip_routing_ecmp") \
- PIPELINE_STAGE(ROUTER, IN, POLICY, 16,
"lr_in_policy") \
- PIPELINE_STAGE(ROUTER, IN, POLICY_ECMP, 17,
"lr_in_policy_ecmp") \
- PIPELINE_STAGE(ROUTER, IN, DHCP_RELAY_RESP_CHK,
18, \
+ PIPELINE_STAGE(ROUTER, IN, POLICY_PRE, 16,
"lr_in_policy_pre") \
+ PIPELINE_STAGE(ROUTER, IN, POLICY, 17,
"lr_in_policy") \
+ PIPELINE_STAGE(ROUTER, IN, POLICY_ECMP, 18,
"lr_in_policy_ecmp") \
+ PIPELINE_STAGE(ROUTER, IN, DHCP_RELAY_RESP_CHK,
19, \
"lr_in_dhcp_relay_resp_chk") \
- PIPELINE_STAGE(ROUTER, IN, DHCP_RELAY_RESP,
19, \
+ PIPELINE_STAGE(ROUTER, IN, DHCP_RELAY_RESP,
20, \
"lr_in_dhcp_relay_resp") \
- PIPELINE_STAGE(ROUTER, IN, ARP_RESOLVE, 20,
"lr_in_arp_resolve") \
- PIPELINE_STAGE(ROUTER, IN, CHK_PKT_LEN, 21,
"lr_in_chk_pkt_len") \
- PIPELINE_STAGE(ROUTER, IN, LARGER_PKTS, 22,
"lr_in_larger_pkts") \
- PIPELINE_STAGE(ROUTER, IN, GW_REDIRECT, 23,
"lr_in_gw_redirect") \
- PIPELINE_STAGE(ROUTER, IN, ARP_REQUEST, 24,
"lr_in_arp_request") \
+ PIPELINE_STAGE(ROUTER, IN, ARP_RESOLVE, 21,
"lr_in_arp_resolve") \
+ PIPELINE_STAGE(ROUTER, IN, CHK_PKT_LEN, 22,
"lr_in_chk_pkt_len") \
+ PIPELINE_STAGE(ROUTER, IN, LARGER_PKTS, 23,
"lr_in_larger_pkts") \
+ PIPELINE_STAGE(ROUTER, IN, GW_REDIRECT, 24,
"lr_in_gw_redirect") \
+ PIPELINE_STAGE(ROUTER, IN, ARP_REQUEST, 25,
"lr_in_arp_request") \
\
/* Logical router egress stages.
*/ \
PIPELINE_STAGE(ROUTER, OUT, CHECK_DNAT_LOCAL,
0, \
diff --git a/ovn-nb.ovsschema b/ovn-nb.ovsschema
index 09361920f..709d32c93 100644
--- a/ovn-nb.ovsschema
+++ b/ovn-nb.ovsschema
@@ -1,7 +1,7 @@
{
"name": "OVN_Northbound",
- "version": "7.8.0",
- "cksum": "3497747919 38626",
+ "version": "7.8.1",
+ "cksum": "884115012 38765",
"tables": {
"NB_Global": {
"columns": {
@@ -524,10 +524,13 @@
"priority": {"type": {"key": {"type": "integer",
"minInteger": 0,
"maxInteger": 32767}}},
+ "chain": {"type": "string"},
"match": {"type": "string"},
"action": {"type": {
"key": {"type": "string",
- "enum": ["set", ["allow", "drop",
"reroute"]]}}},
+ "enum": ["set",
+ ["allow", "drop", "reroute",
"jump"]]}}},
+ "jump_chain": {"type": "string"},
"nexthop": {"type": {"key": "string", "min": 0,
"max": 1}},
"nexthops": {"type": {
"key": "string", "min": 0, "max": "unlimited"}},
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 8373ddb99..6e43e9bc9 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -3942,7 +3942,15 @@ or
<p>
The routing policy's priority. Rules with numerically
higher priority
take precedence over those with lower. A rule is uniquely
identified
- by the priority and match string.
+ by the priority, chain and match string.
+ </p>
+ </column>
+
+ <column name="chain">
+ <p>
+ The routing policy rule's chain name. Only rules with empty
chain name
+ are traversed by default. Other chains are traversed as
response to
+ jump action.
</p>
</column>
@@ -3977,9 +3985,21 @@ or
<code>reroute</code>: Reroute packet to <ref
column="nexthop"/> or
<ref column="nexthops"/>.
</li>
+
+ <li>
+ <code>jump</code>: Start examining rules that have the same
+ <ref column="chain"/> value as specified in
+ <ref column="jump_chain"/>.
+ </li>
</ul>
</column>
+ <column name="jump_chain">
+ <p>
+ The routing policy rule's chain name selected to be examined
next.
+ </p>
+ </column>
+
<column name="nexthop">
<p>
Note: This column is deprecated in favor of <ref
column="nexthops"/>.
diff --git a/tests/ovn-nbctl.at b/tests/ovn-nbctl.at
index 39c02d295..583c3ec74 100644
--- a/tests/ovn-nbctl.at
+++ b/tests/ovn-nbctl.at
@@ -2318,7 +2318,7 @@ dnl
---------------------------------------------------------------------
OVN_NBCTL_TEST([ovn_nbctl_policies], [policies], [
AT_CHECK([ovn-nbctl lr-add lr0])
-dnl Add policies with allow and drop actions
+dnl Add policies with allow, drop and jump actions
AT_CHECK([ovn-nbctl lr-policy-add lr0 100 "ip4.src == 1.1.1.0/24"
drop])
AT_CHECK([ovn-nbctl lr-policy-add lr0 100 "ip4.src == 1.1.2.0/24"
allow pkt_mark=100,foo=bar])
AT_CHECK([ovn-nbctl lr-policy-add lr0 101 "ip4.src == 2.1.1.0/24"
allow])
@@ -2330,6 +2330,8 @@ AT_CHECK([ovn-nbctl --bfd lr-policy-add lr0 103
"ip4.src == 1.2.3.0/24" reroute
AT_CHECK([ovn-nbctl --bfd lr-policy-add lr0 103 "ip4.src ==
1.2.3.0/24" drop], [1], [],
[ovn-nbctl: BFD is valid only with reroute action.
])
+AT_CHECK([ovn-nbctl --chain=inbound lr-policy-add lr0 100 "ip4.src
== 1.1.1.0/24" drop])
+AT_CHECK([ovn-nbctl --chain=outbound lr-policy-add lr0 100 "ip4.src
== 2.1.1.0/24" jump inbound])
dnl Incomplete option set.
AT_CHECK([ovn-nbctl lr-policy-add lr0 200 "ip4.src == 1.1.4.0/24"
reroute 192.168.0.10 foo], [1], [],
@@ -2340,6 +2342,14 @@ AT_CHECK([ovn-nbctl lr-policy-add lr0 200
"ip4.src == 1.1.4.0/24" allow bar=], [
[ovn-nbctl: No value specified for the option : bar
])
+AT_CHECK([ovn-nbctl --chain lr-policy-add lr0 100 "ip4.src ==
1.1.1.0/24" drop], [1], [],
+ [ovn-nbctl: unknown command 'lr0'; use --help for help
+])
+
+AT_CHECK([ovn-nbctl lr-policy-add lr0 100 "ip4.src == 2.1.1.0/24"
jump], [1], [],
+ [ovn-nbctl: Chain name is required when action is jump.
+])
+
dnl Add duplicated policy
AT_CHECK([ovn-nbctl lr-policy-add lr0 100 "ip4.src == 1.1.1.0/24"
drop], [1], [],
[ovn-nbctl: Same routing policy already existed on the logical
router lr0.
@@ -2349,35 +2359,69 @@ AT_CHECK([ovn-nbctl --may-exist lr-policy-add
lr0 100 "ip4.src == 1.1.1.0/24" dr
dnl Add duplicated policy
AT_CHECK([ovn-nbctl lr-policy-add lr0 103 "ip4.src == 1.1.1.0/24"
deny], [1], [],
- [ovn-nbctl: deny: action must be one of "allow", "drop", and
"reroute"
+ [ovn-nbctl: deny: action must be one of "allow", "drop",
"reroute", "jump"
])
dnl Delete by priority and match string
AT_CHECK([ovn-nbctl lr-policy-del lr0 100 "ip4.src == 1.1.1.0/24"])
+
+AT_CHECK([ovn-nbctl lr-policy-list lr0], [0], [dnl
+Routing Policies
+Chain <Default>:
+ 101 ip4.src ==
2.1.1.0/24 allow
+ 101 ip4.src ==
2.1.2.0/24 drop
+ 101 ip6.src ==
2002::/64 drop
+ 100 ip4.src ==
1.1.2.0/24 allow pkt_mark=100,foo=bar
+
+Chain inbound:
+ 100 ip4.src ==
1.1.1.0/24 drop
+
+Chain outbound:
+ 100 ip4.src ==
2.1.1.0/24 jump -> inbound
+])
+
+AT_CHECK([ovn-nbctl --chain inbound lr-policy-del lr0 100 "ip4.src
== 1.1.1.0/24"])
+
AT_CHECK([ovn-nbctl lr-policy-list lr0], [0], [dnl
Routing Policies
+Chain <Default>:
101 ip4.src ==
2.1.1.0/24 allow
101 ip4.src ==
2.1.2.0/24 drop
101 ip6.src ==
2002::/64 drop
100 ip4.src ==
1.1.2.0/24 allow pkt_mark=100,foo=bar
+
+Chain outbound:
+ 100 ip4.src ==
2.1.1.0/24 jump -> inbound
])
dnl Delete all policies for given priority
AT_CHECK([ovn-nbctl lr-policy-del lr0 101])
AT_CHECK([ovn-nbctl lr-policy-list lr0], [0], [dnl
Routing Policies
+Chain <Default>:
100 ip4.src ==
1.1.2.0/24 allow pkt_mark=100,foo=bar
-])
+Chain outbound:
+ 100 ip4.src ==
2.1.1.0/24 jump -> inbound
+])
dnl Delete policy by specified uuid
-uuid=$(ovn-nbctl --bare --column _uuid list logical_router_policy)
+uuid=$(ovn-nbctl --bare --column _uuid find logical_router_policy
chain=\"\")
AT_CHECK([ovn-nbctl lr-policy-del lr0 $uuid])
-AT_CHECK([ovn-nbctl list logical-router-policy], [0], [dnl
+AT_CHECK([ovn-nbctl lr-policy-list lr0], [0], [dnl
+Routing Policies
+
+Chain outbound:
+ 100 ip4.src ==
2.1.1.0/24 jump -> inbound
])
AT_CHECK([ovn-nbctl --if-exists lr-policy-del lr0 $uuid])
+AT_CHECK([ovn-nbctl --chain outbound lr-policy-del lr0])
+
+AT_CHECK([ovn-nbctl lr-policy-list lr0], [0], [dnl
+])
+
dnl Add policy with reroute action
AT_CHECK([ovn-nbctl lr-policy-add lr0 102 "ip4.src == 3.1.2.0/24"
reroute 3.3.3.3])
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index 21d9d63ab..922bc6df3 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -3444,6 +3444,7 @@ AT_CHECK([grep "lr_in_policy" lr0flows3 |
ovn_strip_lflows], [0], [dnl
table=??(lr_in_policy_ecmp ), priority=100 ,
match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 1), action=(reg0 =
172.168.0.101; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13;
outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
table=??(lr_in_policy_ecmp ), priority=100 ,
match=(reg8[[0..15]] == 1 && reg8[[16..31]] == 2), action=(reg0 =
172.168.0.102; reg5 = 172.168.0.100; eth.src = 00:00:20:20:12:13;
outport = "lr0-public"; flags.loopback = 1; reg9[[9]] = 1; next;)
table=??(lr_in_policy_ecmp ), priority=150 ,
match=(reg8[[0..15]] == 0), action=(next;)
+ table=??(lr_in_policy_pre ), priority=0 , match=(1),
action=(reg9[[16..31]] = 0; next;)
])
check ovn-nbctl --wait=sb lr-policy-add lr0 10 "ip4.src ==
10.0.0.4" reroute 172.168.0.101,172.168.0.102,172.168.0.103
@@ -3463,6 +3464,7 @@ sed 's/reg8\[[0..15\]] ==
[[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf
table=??(lr_in_policy_ecmp ), priority=100 ,
match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src =
00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
reg9[[9]] = 1; next;)
table=??(lr_in_policy_ecmp ), priority=100 ,
match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3),
action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src =
00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
reg9[[9]] = 1; next;)
table=??(lr_in_policy_ecmp ), priority=150 ,
match=(reg8[[0..15]] == <cleared>), action=(next;)
+ table=??(lr_in_policy_pre ), priority=0 , match=(1),
action=(reg9[[16..31]] = 0; next;)
])
check ovn-nbctl --wait=sb lr-policy-add lr0 10 "ip4.src ==
10.0.0.5" reroute 172.168.0.110
@@ -3483,6 +3485,7 @@ sed 's/reg8\[[0..15\]] ==
[[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf
table=??(lr_in_policy_ecmp ), priority=100 ,
match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src =
00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
reg9[[9]] = 1; next;)
table=??(lr_in_policy_ecmp ), priority=100 ,
match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3),
action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src =
00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
reg9[[9]] = 1; next;)
table=??(lr_in_policy_ecmp ), priority=150 ,
match=(reg8[[0..15]] == <cleared>), action=(next;)
+ table=??(lr_in_policy_pre ), priority=0 , match=(1),
action=(reg9[[16..31]] = 0; next;)
])
check ovn-nbctl --wait=sb lr-policy-del lr0 10 "ip4.src ==
10.0.0.3"
@@ -3500,6 +3503,7 @@ sed 's/reg8\[[0..15\]] ==
[[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf
table=??(lr_in_policy_ecmp ), priority=100 ,
match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 2),
action=(reg0 = 172.168.0.102; reg5 = 172.168.0.100; eth.src =
00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
reg9[[9]] = 1; next;)
table=??(lr_in_policy_ecmp ), priority=100 ,
match=(reg8[[0..15]] == <cleared> && reg8[[16..31]] == 3),
action=(reg0 = 172.168.0.103; reg5 = 172.168.0.100; eth.src =
00:00:20:20:12:13; outport = "lr0-public"; flags.loopback = 1;
reg9[[9]] = 1; next;)
table=??(lr_in_policy_ecmp ), priority=150 ,
match=(reg8[[0..15]] == <cleared>), action=(next;)
+ table=??(lr_in_policy_pre ), priority=0 , match=(1),
action=(reg9[[16..31]] = 0; next;)
])
check ovn-nbctl --wait=sb lr-policy-del lr0 10 "ip4.src ==
10.0.0.4"
@@ -3513,6 +3517,7 @@ sed 's/reg8\[[0..15\]] ==
[[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf
table=??(lr_in_policy ), priority=10 , match=(ip4.src ==
10.0.0.5), action=(reg0 = 172.168.0.110; reg5 = 172.168.0.100;
eth.src = 00:00:20:20:12:13; outport = "lr0-public"; flags.loopback =
1; reg8[[0..15]] = <cleared>; reg9[[9]] = 1; next;)
table=??(lr_in_policy_ecmp ), priority=0 , match=(1),
action=(drop;)
table=??(lr_in_policy_ecmp ), priority=150 ,
match=(reg8[[0..15]] == <cleared>), action=(next;)
+ table=??(lr_in_policy_pre ), priority=0 , match=(1),
action=(reg9[[16..31]] = 0; next;)
])
check ovn-nbctl --wait=sb add logical_router_policy . nexthops
"2000\:\:b"
@@ -3525,6 +3530,34 @@ sed 's/reg8\[[0..15\]] ==
[[0-9]]*/reg8\[[0..15\]] == <cleared>/' | ovn_strip_lf
table=??(lr_in_policy ), priority=0 , match=(1),
action=(reg8[[0..15]] = <cleared>; next;)
table=??(lr_in_policy_ecmp ), priority=0 , match=(1),
action=(drop;)
table=??(lr_in_policy_ecmp ), priority=150 ,
match=(reg8[[0..15]] == <cleared>), action=(next;)
+ table=??(lr_in_policy_pre ), priority=0 , match=(1),
action=(reg9[[16..31]] = 0; next;)
+])
+
+AT_CLEANUP
+])
+
+OVN_FOR_EACH_NORTHD_NO_HV([
+AT_SETUP([Router policies - chains])
+ovn_start
+
+check ovn-nbctl --wait=sb lr-add lr0
+check ovn-nbctl --wait=sb lr-policy-add lr0 112 "ip4.src ==
10.0.0.0/24" jump nochain
+check ovn-nbctl --wait=sb lr-policy-add lr0 102 "ip4.src ==
10.0.0.0/24" jump inbound
+check ovn-nbctl --wait=sb lr-policy-add lr0 101 "ip4.src ==
10.0.16.0/24" jump inbound
+check ovn-nbctl --wait=sb lr-policy-add lr0 100 "ip4.src ==
192.168.0.1/32" allow
+check ovn-nbctl --wait=sb --chain=inbound lr-policy-add lr0 201 "1"
allow
+
+AT_CHECK([grep -qE "Logical router: lr0, policy action 'jump'
follows to non-existent chain nochain" northd/ovn-northd.log], [0])
+
+ovn-sbctl dump-flows lr0 > lr0flows2
+AT_CAPTURE_FILE([lr0flows2])
+
+AT_CHECK([grep "lr_in_policy[[^_]]" lr0flows2 | ovn_strip_lflows |
sort], [0], [dnl
+ table=??(lr_in_policy ), priority=0 , match=(1),
action=(reg8[[0..15]] = 0; next;)
+ table=??(lr_in_policy ), priority=100 ,
match=(reg9[[16..31]] == 0 && (ip4.src == 192.168.0.1/32)),
action=(reg8[[0..15]] = 0; next;)
+ table=??(lr_in_policy ), priority=101 ,
match=(reg9[[16..31]] == 0 && (ip4.src == 10.0.16.0/24)),
action=(reg9[[16..31]]=1; next(pipeline=ingress, table=??);)
+ table=??(lr_in_policy ), priority=102 ,
match=(reg9[[16..31]] == 0 && (ip4.src == 10.0.0.0/24)),
action=(reg9[[16..31]]=1; next(pipeline=ingress, table=??);)
+ table=??(lr_in_policy ), priority=201 ,
match=(reg9[[16..31]] == 1 && (1)), action=(reg8[[0..15]] = 0; next;)
])
AT_CLEANUP
diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
index 131d9f0bf..0c31a9698 100644
--- a/utilities/ovn-nbctl.c
+++ b/utilities/ovn-nbctl.c
@@ -4091,6 +4091,7 @@ nbctl_pre_lr_policy_add(struct ctl_context *ctx)
ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_policy_col_priority);
ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_policy_col_match);
+ ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_policy_col_chain);
ovsdb_idl_add_column(ctx->idl, &nbrec_bfd_col_dst_ip);
ovsdb_idl_add_column(ctx->idl, &nbrec_bfd_col_logical_port);
@@ -4114,13 +4115,16 @@ nbctl_lr_policy_add(struct ctl_context *ctx)
const char *action = ctx->argv[4];
size_t n_nexthops = 0;
char **nexthops = NULL;
+ const char *chain_s = shash_find_data(&ctx->options, "--chain");
bool reroute = false;
+ bool jump = false;
+
/* Validate action. */
if (strcmp(action, "allow") && strcmp(action, "drop")
- && strcmp(action, "reroute")) {
+ && strcmp(action, "jump") && strcmp(action, "reroute")) {
ctl_error(ctx, "%s: action must be one of \"allow\",
\"drop\", "
- "and \"reroute\"", action);
+ "\"reroute\", \"jump\"", action);
return;
}
if (!strcmp(action, "reroute")) {
@@ -4131,14 +4135,23 @@ nbctl_lr_policy_add(struct ctl_context *ctx)
reroute = true;
}
+ if (!strcmp(action, "jump")) {
+ if (ctx->argc < 6) {
+ ctl_error(ctx, "Chain name is required when action is
jump.");
+ return;
+ }
+ jump = true;
+ }
+
/* Check if same routing policy already exists.
* A policy is uniquely identified by priority and match */
bool may_exist = !!shash_find(&ctx->options, "--may-exist");
size_t i;
for (i = 0; i < lr->n_policies; i++) {
const struct nbrec_logical_router_policy *policy =
lr->policies[i];
- if (policy->priority == priority &&
- !strcmp(policy->match, ctx->argv[3])) {
+ if (policy->priority == priority
+ && !strcmp(policy->match, ctx->argv[3])
+ && !strcmp(policy->chain, (chain_s) ? chain_s : "")) {
if (!may_exist) {
ctl_error(ctx, "Same routing policy already existed
on the "
"logical router %s.", ctx->argv[1]);
@@ -4200,6 +4213,15 @@ nbctl_lr_policy_add(struct ctl_context *ctx)
nbrec_logical_router_policy_set_priority(policy, priority);
nbrec_logical_router_policy_set_match(policy, ctx->argv[3]);
nbrec_logical_router_policy_set_action(policy, action);
+
+ if (chain_s) {
+ nbrec_logical_router_policy_set_chain(policy, chain_s);
+ }
+
+ if (jump) {
+ nbrec_logical_router_policy_set_jump_chain(policy,
ctx->argv[5]);
+ }
+
if (reroute) {
nbrec_logical_router_policy_set_nexthops(
policy, (const char **)nexthops, n_nexthops);
@@ -4207,7 +4229,7 @@ nbctl_lr_policy_add(struct ctl_context *ctx)
/* Parse the options. */
struct smap options = SMAP_INITIALIZER(&options);
- for (i = reroute ? 6 : 5; i < ctx->argc; i++) {
+ for (i = (reroute | jump) ? 6 : 5; i < ctx->argc; i++) {
char *key, *value;
value = xstrdup(ctx->argv[i]);
key = strsep(&value, "=");
@@ -4319,84 +4341,81 @@ nbctl_pre_lr_policy_del(struct ctl_context *ctx)
ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_policy_col_priority);
ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_policy_col_match);
+ ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_policy_col_chain);
}
static void
nbctl_lr_policy_del(struct ctl_context *ctx)
{
const struct nbrec_logical_router *lr;
- int64_t priority = 0;
char *error = lr_by_name_or_uuid(ctx, ctx->argv[1], true, &lr);
+
if (error) {
ctx->error = error;
return;
}
- if (ctx->argc == 2) {
- /* If a priority is not specified, delete all policies. */
+ const char *chain = shash_find_data(&ctx->options, "--chain");
+
+ if (!chain) {
+ chain = "";
+ }
+
+ /* An uuid or priority either chain are not specified.
+ Delete all policies for lr */
+ if (ctx->argc == 2 && !*chain) {
nbrec_logical_router_set_policies(lr, NULL, 0);
return;
}
- const struct uuid *lr_policy_uuid = NULL;
+ int64_t priority = 0;
struct uuid uuid_from_cmd;
- if (uuid_from_string(&uuid_from_cmd, ctx->argv[2])) {
- lr_policy_uuid = &uuid_from_cmd;
- } else {
- error = parse_priority(ctx->argv[2], &priority);
- if (error) {
- ctx->error = error;
- return;
- }
- }
- /* If uuid was specified, delete routing policy with the
- * specified uuid. */
- if (ctx->argc == 3) {
- size_t i;
- if (lr_policy_uuid) {
- for (i = 0; i < lr->n_policies; i++) {
- if (uuid_equals(lr_policy_uuid,
- &(lr->policies[i]->header_.uuid))) {
- nbrec_logical_router_update_policies_delvalue(
- lr, lr->policies[i]);
- break;
- }
- }
- if (i == lr->n_policies) {
- if (!shash_find(&ctx->options, "--if-exists")) {
- ctl_error(ctx, "Logical router policy uuid is
not found.");
- }
+ /* An uuid is specified, delete the policy with uuid only */
+ if (ctx->argc == 3 && uuid_from_string(&uuid_from_cmd,
ctx->argv[2])) {
+ for (int i = 0; i < lr->n_policies; i++) {
+ if (uuid_equals(&uuid_from_cmd,
+ &(lr->policies[i]->header_.uuid))) {
+ nbrec_logical_router_update_policies_delvalue(
+ lr, lr->policies[i]);
return;
}
+ }
- /* If match is not specified, delete all routing policies
with the
- * specified priority. */
- } else {
- for (i = 0; i < lr->n_policies; i++) {
- if (priority == lr->policies[i]->priority) {
- nbrec_logical_router_update_policies_delvalue(
- lr, lr->policies[i]);
- }
- }
+ if (!shash_find(&ctx->options, "--if-exists")) {
+ ctl_error(ctx, "Logical router policy uuid is not found.");
}
+
return;
}
- /* Delete policy that has the same priority and match string */
- for (int i = 0; i < lr->n_policies; i++) {
- struct nbrec_logical_router_policy *routing_policy =
lr->policies[i];
- if (priority == routing_policy->priority &&
- !strcmp(ctx->argv[3], routing_policy->match)) {
- nbrec_logical_router_update_policies_delvalue(lr,
routing_policy);
+ if (ctx->argc >= 3) {
+ error = parse_priority(ctx->argv[2], &priority);
+ if (error) {
+ ctx->error = error;
return;
}
}
+
+ char *match = (ctx->argc == 4) ? ctx->argv[3] : NULL;
+
+ for (int i = 0; i < lr->n_policies; i++) {
+ struct nbrec_logical_router_policy *policy = lr->policies[i];
+
+ /* Delete policies selected by chain, priority (if set),
+ match (if set). Sure, at least one option is set here */
+ if ((!priority || priority == policy->priority)
+ && (!strcmp(chain, policy->chain))
+ && (!match || !strcmp(match, policy->match))) {
+ nbrec_logical_router_update_policies_delvalue(lr, policy);
+ }
+ }
}
- struct routing_policy {
+struct routing_policy {
int priority;
char *match;
+ char *chain;
const struct nbrec_logical_router_policy *policy;
};
@@ -4405,6 +4424,12 @@ routing_policy_cmp(const void *policy1_,
const void *policy2_)
{
const struct routing_policy *policy1p = policy1_;
const struct routing_policy *policy2p = policy2_;
+ int chain_match = strcmp(policy1p->chain, policy2p->chain);
+
+ if (chain_match) {
+ return chain_match;
+ }
+
if (policy1p->priority != policy2p->priority) {
return policy1p->priority > policy2p->priority ? -1 : 1;
} else {
@@ -4416,17 +4441,18 @@ static void
print_routing_policy(const struct nbrec_logical_router_policy *policy,
struct ds *s)
{
- if (policy->n_nexthops) {
- ds_put_format(s, "%10"PRId64" %50s %15s", policy->priority,
- policy->match, policy->action);
- for (int i = 0; i < policy->n_nexthops; i++) {
- char *next_hop = normalize_prefix_str(policy->nexthops[i]);
- ds_put_format(s, i ? ", %s" : " %25s", next_hop ?
next_hop : "");
- free(next_hop);
- }
- } else {
- ds_put_format(s, "%10"PRId64" %50s %15s", policy->priority,
- policy->match, policy->action);
+ ds_put_format(s, "%10"PRId64" %50s %15s",
+ policy->priority, policy->match, policy->action);
+
+ if (strcmp(policy->action, "jump") == 0
+ && policy->jump_chain && *policy->jump_chain) {
+ ds_put_format(s, " -> %s", policy->jump_chain);
+ }
+
+ for (int i = 0; i < policy->n_nexthops; i++) {
+ char *next_hop = normalize_prefix_str(policy->nexthops[i]);
+ ds_put_format(s, i ? ", %s" : " %25s", next_hop ? next_hop :
"");
+ free(next_hop);
}
if (!smap_is_empty(&policy->options) ||
policy->n_bfd_sessions) {
@@ -4457,6 +4483,9 @@ nbctl_pre_lr_policy_list(struct ctl_context *ctx)
ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_policy_col_options);
ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_policy_col_bfd_sessions);
+ ovsdb_idl_add_column(ctx->idl,
&nbrec_logical_router_policy_col_chain);
+ ovsdb_idl_add_column(ctx->idl,
+ &nbrec_logical_router_policy_col_jump_chain);
}
static void
@@ -4476,6 +4505,7 @@ nbctl_lr_policy_list(struct ctl_context *ctx)
= lr->policies[i];
policies[n_policies].priority = policy->priority;
policies[n_policies].match = policy->match;
+ policies[n_policies].chain = (policy->chain) ? policy->chain
: "";
policies[n_policies].policy = policy;
n_policies++;
}
@@ -4483,9 +4513,31 @@ nbctl_lr_policy_list(struct ctl_context *ctx)
if (n_policies) {
ds_put_cstr(&ctx->output, "Routing Policies\n");
}
+
+ /* Print chain headings only if there are non-default chains.
+ Otherwise print format will be fully backward compatible.
+ Note that at this point policies are sorted out by chain
names too.
+ */
+ char *chain_current;
+ int print_chain_head = (n_policies
+ && policies[n_policies - 1].chain[0]);
+
for (int i = 0; i < n_policies; i++) {
+ /* Print chain heading */
+ if (print_chain_head
+ && (i == 0
+ || strcmp(chain_current, policies[i].chain))) {
+ chain_current = policies[i].chain;
+ if (*chain_current) {
+ ds_put_format(&ctx->output, "\nChain %s:\n",
chain_current);
+ } else {
+ ds_put_format(&ctx->output, "Chain <Default>:\n");
+ }
+ }
+
print_routing_policy(policies[i].policy, &ctx->output);
}
+
free(policies);
}
@@ -8091,10 +8143,11 @@ static const struct ctl_command_syntax
nbctl_commands[] = {
/* Policy commands */
{ "lr-policy-add", 4, INT_MAX,
"ROUTER PRIORITY MATCH ACTION [NEXTHOP] [OPTIONS - KEY=VALUE
...]",
- nbctl_pre_lr_policy_add, nbctl_lr_policy_add, NULL,
"--may-exist,--bfd?",
- RW },
+ nbctl_pre_lr_policy_add, nbctl_lr_policy_add, NULL,
+ "--may-exist,--bfd?,--chain=", RW },
{ "lr-policy-del", 1, 3, "ROUTER [{PRIORITY | UUID} [MATCH]]",
- nbctl_pre_lr_policy_del, nbctl_lr_policy_del, NULL,
"--if-exists", RW },
+ nbctl_pre_lr_policy_del, nbctl_lr_policy_del, NULL,
+ "--if-exists,--chain=", RW },
{ "lr-policy-list", 1, 1, "ROUTER", nbctl_pre_lr_policy_list,
nbctl_lr_policy_list, NULL, "", RO },