On Wed, Nov 6, 2024 at 9:06 AM Aleksandr Smirnov (K2 Cloud)
<[email protected]> wrote:
>
> On 10/21/24 9:41 PM, Han Zhou wrote:
> > On Mon, Oct 21, 2024 at 7:03 AM Aleksandr Smirnov <[email protected]> 
> > wrote:
> >> This is RFC proposal, the code below is a working prototype, unit test is 
> >> not ready to look into.
> >>
> >> 1. Introduction
> >>
> >> The objective is to enchance routing policies to organize them as set of 
> >> independent lists,
> >> here 'chains', and allow to select and traverse chains depending on match 
> >> conditions.
> >>
> >> Every routing policy rule have assigned chain name, a type of string, or 
> >> an empty string.
> >> Rule actions have new action 'jump' with string argument that allows to 
> >> switch
> >> rule's traversal to given chain.
> >>
> >> 2. New traversal flow.
> >>
> >> The flow starts rule's traversal for only those having an empty chain name,
> >> accoring to their priorities.
> >> If match occurs on rule having the 'jump' action, a traversal restarts for 
> >> rules
> >> that belongs to that chain, again, accoring to their priorities.
> >> Any other actions will stop router policy flow.
> >> (i.e. 'jump' have meaning of 'goto' but not 'call/return').
> >>
> >> 3. Change of utilities
> >>
> >> ovn-nbctl is changed to accept and report new options.
> >>
> >> ovn-nbctl lr-policy-add accepts chain name as optional argument.
> >>
> >>      ovn-nbctl [--chain Name] lr-policy-add ...
> >>
> >>      If omitted, chain name will be empty (i.e. rule added will belong to 
> >> default flow)
> >>
> >> ovn-nbctl lr-policy-add accepts new action 'jump'
> >>
> >>      ovn-nbctl lr-policy-add ... jump Name
> >>
> >> ovn-nbctl lr-policy-list changes its output format
> >>      to print chain name in first column
> >>      to print jump actions
> >>
> >> 4. Changes in NB DB schema
> >>
> >> Logical_Router_Policy:
> >>      New field:
> >>          Name: chain
> >>          Type: string
> >>      New field:
> >>          Name: jump_chain
> >>          Type: string
> >>      Modified field:
> >>          Name: actions
> >>          Value: add enum value 'jump'
> >>
> >> 5. Change in the SB DB generation
> >>
> >>      1. Reserve one 16 bit register to hold chain ID numeric value
> >>         designating current chain to traverse (here for example Rx[0..15])
> >>      2. Reserve new stage at LR, ingress, to make initial assignment to 
> >> Rx[0..15] := 0
> >>      3. Generate router policy flow in the following manner:
> >>          3.1 lr_in_ip_routing_ecmp  (not changed)
> >>          3.2 lr_in_policy_pre
> >>                  match:  1
> >>                  actoin: Rx[0..15] = 0; next;
> >>          3.3 lr_in_policy
> >>                  match: (Rx[0..15] == <chain_id>) && (<nb:match>)
> >>                  action: <nb:action_not_jump>
> >>                          | 'Rx[0..15] = <jump_chain_id>; next(ingress, 
> >> lr_in_policy);'
> >>
> >> Signed-off-by: Aleksandr Smirnov <[email protected]>
> >> ---
> >> RFC: First post.
> > Thanks Aleksandr. This idea looks good to me in general. I didn't
> > review in much detail since it is RFC. Just some reminders:
> > - We need to document the register usage carefully and make sure it
> > does not conflict with other features for the router pipeline.
> > - Do we need a mechanism to avoid looping forever in the chains?
> > Probably by maintaining a counter of jumps and check if it reaches the
> > max allowed count then drop?
> >
> > Regards,
> > Han
>
> Hello Han,
>
> I apologise for late answer, I has been urgently assigned to find/fix
> openvswitch kmod kernel crash.
>
> Answering your questions:
>
> 1. I looked into northd register usage and see that
>
>     REG_ORIG_TP_DPORT_ROUTER   "reg9[16..31]"
>
>    could be reused to policing purposes.
>
>    I see no other options because xxreg0, xxreg1 are in-use, reg8 is
> also in-use for ECMP processing.
>
>    However, I have a question: I see there are sixteen registers defined
> but northd is using only reg0..reg9.
>
>    Why it is? Can we use other registers?

reg10 onwards is used by ovn-controller to store inport, outport and
conntrack zones.

Numan

>
> 2. Seems we already have flow loop protection in the vSwitch. Here is my
> findings from OVS:
>
>  >>While processing a given packet, Open vSwitch limits the flow table
> recursion depth to 64, to en-
>  >>sure that packet processing uses a finite amount of time and space.
> Actions that count against the
>  >>recursion limit include resubmit from a given OpenFlow table to the
> same or an earlier table,
>  >>group, and output to patch ports.
>
> Thus, I think I do not need to provde extra care against infinite flow loops
>
>
> Thank you,
>
> Alexander
>
>
> >> ---
> >>   northd/northd.c       | 68 ++++++++++++++++++++++++++++++++++++++++---
> >>   northd/northd.h       | 19 ++++++------
> >>   ovn-nb.ovsschema      |  8 +++--
> >>   ovn-nb.xml            | 21 ++++++++++++-
> >>   tests/ovn-nbctl.at    | 17 +++++++++--
> >>   tests/ovn-northd.at   | 14 ++++++++-
> >>   utilities/ovn-nbctl.c | 56 ++++++++++++++++++++++++++++-------
> >>   7 files changed, 172 insertions(+), 31 deletions(-)
> >>
> >> diff --git a/northd/northd.c b/northd/northd.c
> >> index 0fe15ac59..0639b4881 100644
> >> --- a/northd/northd.c
> >> +++ b/northd/northd.c
> >> @@ -189,6 +189,7 @@ BUILD_ASSERT_DECL(ACL_OBS_STAGE_MAX < (1 << 2));
> >>   #define REG_SRC_IPV4 "reg1"
> >>   #define REG_SRC_IPV6 "xxreg1"
> >>   #define REG_DHCP_RELAY_DIP_IPV4 "reg2"
> >> +#define REG_POLICY_CHAIN_ID "reg6[0..15]"
> >>   #define REG_ROUTE_TABLE_ID "reg7"
> >>
> >>   /* Register used to store backend ipv6 address
> >> @@ -10756,11 +10757,50 @@ static bool check_bfd_state(const struct 
> >> nbrec_logical_router_policy *rule,
> >>       return true;
> >>   }
> >>
> >> +
> >> +
> >> +static uint32_t
> >> +policy_chain_add(struct simap *chain_ids,
> >> +                 const char *chain_name)
> >> +{
> >> +    uint32_t id = simap_count(chain_ids) + 1;
> >> +
> >> +    if (id == UINT16_MAX) {
> >> +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> >> +        VLOG_WARN_RL(&rl, "too many policy chains for Logical Router.");
> >> +        return 0;
> >> +    }
> >> +
> >> +    if (!simap_put(chain_ids, chain_name, id)) {
> >> +        static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 1);
> >> +        VLOG_WARN_RL(&rl, "Policy chain id unexpectedly appeared");
> >> +    }
> >> +
> >> +    return id;
> >> +}
> >> +
> >> +static uint32_t
> >> +policy_chain_id(struct simap *chain_ids,
> >> +                const char *chain_name)
> >> +{
> >> +    if (!chain_name || !chain_name[0]) {
> >> +        return 0;
> >> +    }
> >> +
> >> +    uint32_t id = simap_get(chain_ids, chain_name);
> >> +    if (!id) {
> >> +        id = policy_chain_add(chain_ids, chain_name);
> >> +    }
> >> +
> >> +    return id;
> >> +}
> >> +
> >>   static void
> >>   build_routing_policy_flow(struct lflow_table *lflows, struct 
> >> ovn_datapath *od,
> >>                             const struct hmap *lr_ports, struct 
> >> route_policy *rp,
> >>                             const struct ovsdb_idl_row *stage_hint,
> >> -                          struct lflow_ref *lflow_ref)
> >> +                          struct lflow_ref *lflow_ref,
> >> +                          struct simap *chain_ids)
> >>   {
> >>       const struct nbrec_logical_router_policy *rule = rp->rule;
> >>       struct ds match = DS_EMPTY_INITIALIZER;
> >> @@ -10808,7 +10848,12 @@ build_routing_policy_flow(struct lflow_table 
> >> *lflows, struct ovn_datapath *od,
> >>                         lrp_addr_s,
> >>                         out_port->lrp_networks.ea_s,
> >>                         out_port->json_key);
> >> -
> >> +    } else if (!strcmp(rule->action, "jump")) {
> >> +        ds_put_format(&actions,
> >> +                      "%s=%d; next(pipeline=ingress,table=%d);",
> >> +                      REG_POLICY_CHAIN_ID,
> >> +                      policy_chain_id(chain_ids, rule->jump_chain),
> >> +                      ovn_stage_get_table(S_ROUTER_IN_POLICY));
> >>       } else if (!strcmp(rule->action, "drop")) {
> >>           ds_put_cstr(&actions, debug_drop_action());
> >>       } else if (!strcmp(rule->action, "allow")) {
> >> @@ -10818,7 +10863,9 @@ build_routing_policy_flow(struct lflow_table 
> >> *lflows, struct ovn_datapath *od,
> >>           }
> >>           ds_put_cstr(&actions, REG_ECMP_GROUP_ID" = 0; next;");
> >>       }
> >> -    ds_put_format(&match, "%s", rule->match);
> >> +
> >> +    ds_put_format(&match, "%s == %d && (%s)", REG_POLICY_CHAIN_ID,
> >> +                  policy_chain_id(chain_ids, rule->chain), rule->match);
> >>
> >>       ovn_lflow_add_with_hint(lflows, od, S_ROUTER_IN_POLICY, 
> >> rule->priority,
> >>                               ds_cstr(&match), ds_cstr(&actions), 
> >> stage_hint,
> >> @@ -13804,9 +13851,15 @@ build_ingress_policy_flows_for_lrouter(
> >>       ovs_assert(od->nbr);
> >>       /* 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);
> >> @@ -13816,6 +13869,10 @@ build_ingress_policy_flows_for_lrouter(
> >>       /* Convert routing policies to flows. */
> >>       uint16_t ecmp_group_id = 1;
> >>       struct route_policy *rp;
> >> +    struct simap chain_ids;
> >> +
> >> +    simap_init(&chain_ids);
> >> +
> >>       HMAP_FOR_EACH_WITH_HASH (rp, key_node, uuid_hash(&od->key),
> >>                                route_policies) {
> >>           const struct nbrec_logical_router_policy *rule = rp->rule;
> >> @@ -13828,9 +13885,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 8f76d642d..c711e2587 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 b4a395c56..b81647fa1 100644
> >> --- a/ovn-nb.ovsschema
> >> +++ b/ovn-nb.ovsschema
> >> @@ -1,7 +1,7 @@
> >>   {
> >>       "name": "OVN_Northbound",
> >> -    "version": "7.6.0",
> >> -    "cksum": "2171465655 38284",
> >> +    "version": "7.6.1",
> >> +    "cksum": "2213857026 38387",
> >>       "tables": {
> >>           "NB_Global": {
> >>               "columns": {
> >> @@ -518,10 +518,12 @@
> >>                   "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 2836f58f5..4476c7e7e 100644
> >> --- a/ovn-nb.xml
> >> +++ b/ovn-nb.xml
> >> @@ -3906,7 +3906,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. Others chains are traversed as responce to
> >> +        jump action.
> >>         </p>
> >>       </column>
> >>
> >> @@ -3941,9 +3949,20 @@ or
> >>             <code>reroute</code>: Reroute packet to <ref 
> >> column="nexthop"/> or
> >>             <ref column="nexthops"/>.
> >>           </li>
> >> +
> >> +        <li>
> >> +          <code>jump</code>: Restart rules traversal for those having 
> >> chain
> >> +          name equal to <ref column="jump_chain"/>.
> >> +        </li>
> >>         </ul>
> >>       </column>
> >>
> >> +    <column name="jump_chain">
> >> +      <p>
> >> +        The routing policy rule's chain name selected to traverse.
> >> +      </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 2efa13b93..7795d5ed4 100644
> >> --- a/tests/ovn-nbctl.at
> >> +++ b/tests/ovn-nbctl.at
> >> @@ -2288,11 +2288,22 @@ OVN_NBCTL_TEST([ovn_nbctl_policies], [policies], [
> >>   AT_CHECK([ovn-nbctl lr-add lr0])
> >>
> >>   dnl Add policies with allow and drop 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 --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" allow])
> >> +AT_CHECK([ovn-nbctl lr-policy-add lr0 101 "ip4.src == 2.1.2.0/24" jump 
> >> "inbound"])
> >> +AT_CHECK([ovn-nbctl --chain "inbound" lr-policy-add lr0 101 "ip4.src == 
> >> 1.1.2.0/24" allow pkt_mark=100,foo=bar])
> >> +AT_CHECK([ovn-nbctl lr-policy-add lr0 11 "ip6.src == 2002::/64" jump 
> >> "outbound"])
> >> +
> >> +ovn-nbctl list Logical_Router_Policy
> >> +ovn-nbctl lr-policy-list lr0
> >> +
> >>   AT_CHECK([ovn-nbctl lr-policy-add lr0 101 "ip4.src == 2.1.1.0/24" allow])
> >>   AT_CHECK([ovn-nbctl lr-policy-add lr0 101 "ip4.src == 2.1.2.0/24" drop])
> >> -AT_CHECK([ovn-nbctl lr-policy-add lr0 101 "ip6.src == 2002::/64" drop])
> >> +
> >> +
> >> +
> >> +
> >> +
> >>   AT_CHECK([ovn-nbctl --bfd lr-policy-add lr0 103 "ip4.src == 1.2.3.0/24" 
> >> reroute 192.168.1.1], [1], [],
> >>     [ovn-nbctl: out lrp not found for 192.168.1.1 nexthop
> >>   ])
> >> diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
> >> index d6a8c4640..f423242b9 100644
> >> --- a/tests/ovn-northd.at
> >> +++ b/tests/ovn-northd.at
> >> @@ -3419,7 +3419,19 @@ check ovn-nbctl lsp-set-type public-lr0 router
> >>   check ovn-nbctl lsp-set-addresses public-lr0 router
> >>   check ovn-nbctl lsp-set-options public-lr0 router-port=lr0-public
> >>
> >> -check ovn-nbctl --wait=sb lr-policy-add lr0  10 "ip4.src == 10.0.0.3" 
> >> reroute 172.168.0.101,172.168.0.102
> >> +###check ovn-nbctl --wait=sb lr-policy-add lr0  10 "ip4.src == 10.0.0.3" 
> >> reroute 172.168.0.101,172.168.0.102
> >> +
> >> +AT_CHECK([ovn-nbctl --chain "inbound" lr-policy-add lr0 100 "ip4.src == 
> >> 1.1.1.0/24" drop])
> >> +AT_CHECK([ovn-nbctl --chain "inbound" lr-policy-add lr0 100 "ip4.src == 
> >> 1.1.2.0/24" allow pkt_mark=100,foo=bar])
> >> +AT_CHECK([ovn-nbctl --chain "outbound" lr-policy-add lr0 101 "ip4.src == 
> >> 2.1.1.0/24" allow])
> >> +AT_CHECK([ovn-nbctl lr-policy-add lr0 101 "ip4.src == 2.1.2.0/24" jump 
> >> "inbound"])
> >> +AT_CHECK([ovn-nbctl lr-policy-add lr0 101 "ip6.src == 2002::/64" jump 
> >> "outbound"])
> >> +
> >> +ovn-nbctl list Logical_Router_Policy
> >> +
> >> +sleep 1
> >> +
> >> +ovn-sbctl lflow-list lr0
> >>
> >>   ovn-nbctl lr-policy-list lr0 > policy-list
> >>   AT_CAPTURE_FILE([policy-list])
> >> diff --git a/utilities/ovn-nbctl.c b/utilities/ovn-nbctl.c
> >> index d45be75c7..13277db66 100644
> >> --- a/utilities/ovn-nbctl.c
> >> +++ b/utilities/ovn-nbctl.c
> >> @@ -4116,11 +4116,13 @@ nbctl_lr_policy_add(struct ctl_context *ctx)
> >>       char **nexthops = NULL;
> >>
> >>       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,6 +4133,14 @@ nbctl_lr_policy_add(struct ctl_context *ctx)
> >>           reroute = true;
> >>       }
> >>
> >> +    if (!strcmp(action, "jump")) {
> >> +        if (ctx->argc < 6) {
> >> +            ctl_error(ctx, "Chain number 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");
> >> @@ -4195,11 +4205,22 @@ nbctl_lr_policy_add(struct ctl_context *ctx)
> >>           free(nexthops_arg);
> >>       }
> >>
> >> +    const char *chain_s = shash_find_data(&ctx->options, "--chain");
> >> +
> >>       struct nbrec_logical_router_policy *policy;
> >>       policy = nbrec_logical_router_policy_insert(ctx->txn);
> >>       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 +4228,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, "=");
> >> @@ -4394,9 +4415,10 @@ nbctl_lr_policy_del(struct ctl_context *ctx)
> >>       }
> >>   }
> >>
> >> - struct routing_policy {
> >> +struct routing_policy {
> >>       int priority;
> >>       char *match;
> >> +    char *chain;
> >>       const struct nbrec_logical_router_policy *policy;
> >>   };
> >>
> >> @@ -4405,6 +4427,13 @@ 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 +4445,21 @@ static void
> >>   print_routing_policy(const struct nbrec_logical_router_policy *policy,
> >>                        struct ds *s)
> >>   {
> >> +    ds_put_format(s, "%25s %10"PRId64" %50s %15s",
> >> +                  (*policy->chain) ? policy->chain : "",
> >> +                  policy->priority, policy->match, policy->action);
> >> +
> >> +    if (strcmp(policy->action, "jump") == 0
> >> +        && *policy->jump_chain) {
> >> +        ds_put_format(s, " %s", policy->jump_chain);
> >> +    }
> >> +
> >>       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);
> >>       }
> >>
> >>       if (!smap_is_empty(&policy->options) || policy->n_bfd_sessions) {
> >> @@ -4457,6 +4490,8 @@ 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 +4511,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;
> >>           policies[n_policies].policy = policy;
> >>           n_policies++;
> >>       }
> >> @@ -8100,7 +8136,7 @@ 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?",
> >> +     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 },
> >> --
> >> 2.47.0
> >>
> >> _______________________________________________
> >> dev mailing list
> >> [email protected]
> >> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
>
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to