LCOV - code coverage report
Current view: top level - ovn/controller - pinctrl.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 555 639 86.9 %
Date: 2016-09-14 01:02:56 Functions: 38 39 97.4 %
Branches: 196 316 62.0 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (c) 2015, 2016 Red Hat, Inc.
       2                 :            :  *
       3                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       4                 :            :  * you may not use this file except in compliance with the License.
       5                 :            :  * You may obtain a copy of the License at:
       6                 :            :  *
       7                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       8                 :            :  *
       9                 :            :  * Unless required by applicable law or agreed to in writing, software
      10                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      11                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :            :  * See the License for the specific language governing permissions and
      13                 :            :  * limitations under the License.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <config.h>
      17                 :            : 
      18                 :            : #include "pinctrl.h"
      19                 :            : 
      20                 :            : #include "coverage.h"
      21                 :            : #include "csum.h"
      22                 :            : #include "dirs.h"
      23                 :            : #include "dp-packet.h"
      24                 :            : #include "flow.h"
      25                 :            : #include "lport.h"
      26                 :            : #include "nx-match.h"
      27                 :            : #include "ovn-controller.h"
      28                 :            : #include "lib/packets.h"
      29                 :            : #include "lib/sset.h"
      30                 :            : #include "openvswitch/ofp-actions.h"
      31                 :            : #include "openvswitch/ofp-msgs.h"
      32                 :            : #include "openvswitch/ofp-print.h"
      33                 :            : #include "openvswitch/ofp-util.h"
      34                 :            : #include "openvswitch/vlog.h"
      35                 :            : 
      36                 :            : #include "lib/dhcp.h"
      37                 :            : #include "ovn-controller.h"
      38                 :            : #include "ovn/actions.h"
      39                 :            : #include "ovn/lib/logical-fields.h"
      40                 :            : #include "ovn/lib/ovn-dhcp.h"
      41                 :            : #include "ovn/lib/ovn-util.h"
      42                 :            : #include "poll-loop.h"
      43                 :            : #include "rconn.h"
      44                 :            : #include "socket-util.h"
      45                 :            : #include "timeval.h"
      46                 :            : #include "vswitch-idl.h"
      47                 :            : 
      48                 :         94 : VLOG_DEFINE_THIS_MODULE(pinctrl);
      49                 :            : 
      50                 :            : /* OpenFlow connection to the switch. */
      51                 :            : static struct rconn *swconn;
      52                 :            : 
      53                 :            : /* Last seen sequence number for 'swconn'.  When this differs from
      54                 :            :  * rconn_get_connection_seqno(rconn), 'swconn' has reconnected. */
      55                 :            : static unsigned int conn_seq_no;
      56                 :            : 
      57                 :            : static void pinctrl_handle_put_mac_binding(const struct flow *md,
      58                 :            :                                            const struct flow *headers,
      59                 :            :                                            bool is_arp);
      60                 :            : static void init_put_mac_bindings(void);
      61                 :            : static void destroy_put_mac_bindings(void);
      62                 :            : static void run_put_mac_bindings(struct controller_ctx *,
      63                 :            :                                  const struct lport_index *lports);
      64                 :            : static void wait_put_mac_bindings(struct controller_ctx *);
      65                 :            : static void flush_put_mac_bindings(void);
      66                 :            : 
      67                 :            : static void init_send_garps(void);
      68                 :            : static void destroy_send_garps(void);
      69                 :            : static void send_garp_wait(void);
      70                 :            : static void send_garp_run(const struct ovsrec_bridge *,
      71                 :            :                           const char *chassis_id,
      72                 :            :                           const struct lport_index *lports,
      73                 :            :                           struct hmap *local_datapaths);
      74                 :            : static void pinctrl_handle_nd_na(const struct flow *ip_flow,
      75                 :            :                                  const struct match *md,
      76                 :            :                                  struct ofpbuf *userdata);
      77                 :            : static void reload_metadata(struct ofpbuf *ofpacts,
      78                 :            :                             const struct match *md);
      79                 :            : 
      80                 :       1930 : COVERAGE_DEFINE(pinctrl_drop_put_mac_binding);
      81                 :            : 
      82                 :            : void
      83                 :         44 : pinctrl_init(void)
      84                 :            : {
      85                 :         44 :     swconn = rconn_create(5, 0, DSCP_DEFAULT, 1 << OFP13_VERSION);
      86                 :         44 :     conn_seq_no = 0;
      87                 :         44 :     init_put_mac_bindings();
      88                 :         44 :     init_send_garps();
      89                 :         44 : }
      90                 :            : 
      91                 :            : static ovs_be32
      92                 :        369 : queue_msg(struct ofpbuf *msg)
      93                 :            : {
      94                 :        369 :     const struct ofp_header *oh = msg->data;
      95                 :        369 :     ovs_be32 xid = oh->xid;
      96                 :            : 
      97                 :        369 :     rconn_send(swconn, msg, NULL);
      98                 :        369 :     return xid;
      99                 :            : }
     100                 :            : 
     101                 :            : /* Sets up 'swconn', a newly (re)connected connection to a switch. */
     102                 :            : static void
     103                 :         46 : pinctrl_setup(struct rconn *swconn)
     104                 :            : {
     105                 :            :     /* Fetch the switch configuration.  The response later will allow us to
     106                 :            :      * change the miss_send_len to UINT16_MAX, so that we can enable
     107                 :            :      * asynchronous messages. */
     108                 :         46 :     queue_msg(ofpraw_alloc(OFPRAW_OFPT_GET_CONFIG_REQUEST,
     109                 :         46 :                            rconn_get_version(swconn), 0));
     110                 :            : 
     111                 :            :     /* Set a packet-in format that supports userdata.  */
     112                 :         46 :     queue_msg(ofputil_make_set_packet_in_format(rconn_get_version(swconn),
     113                 :            :                                                 NXPIF_NXT_PACKET_IN2));
     114                 :         46 : }
     115                 :            : 
     116                 :            : static void
     117                 :         46 : set_switch_config(struct rconn *swconn,
     118                 :            :                   const struct ofputil_switch_config *config)
     119                 :            : {
     120                 :         46 :     enum ofp_version version = rconn_get_version(swconn);
     121                 :         46 :     struct ofpbuf *request = ofputil_encode_set_config(config, version);
     122                 :         46 :     queue_msg(request);
     123                 :         46 : }
     124                 :            : 
     125                 :            : static void
     126                 :        217 : pinctrl_handle_arp(const struct flow *ip_flow, const struct match *md,
     127                 :            :                    struct ofpbuf *userdata)
     128                 :            : {
     129                 :            :     /* This action only works for IP packets, and the switch should only send
     130                 :            :      * us IP packets this way, but check here just to be sure. */
     131         [ -  + ]:        217 :     if (ip_flow->dl_type != htons(ETH_TYPE_IP)) {
     132                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     133         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "ARP action on non-IP packet (Ethertype %"PRIx16")",
     134                 :            :                      ntohs(ip_flow->dl_type));
     135                 :          0 :         return;
     136                 :            :     }
     137                 :            : 
     138                 :            :     /* Compose an ARP packet. */
     139                 :            :     uint64_t packet_stub[128 / 8];
     140                 :            :     struct dp_packet packet;
     141                 :        217 :     dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
     142                 :        217 :     compose_arp__(&packet);
     143                 :            : 
     144                 :        217 :     struct eth_header *eth = dp_packet_l2(&packet);
     145                 :        217 :     eth->eth_dst = ip_flow->dl_dst;
     146                 :        217 :     eth->eth_src = ip_flow->dl_src;
     147                 :            : 
     148                 :        217 :     struct arp_eth_header *arp = dp_packet_l3(&packet);
     149                 :        217 :     arp->ar_op = htons(ARP_OP_REQUEST);
     150                 :        217 :     arp->ar_sha = ip_flow->dl_src;
     151                 :        217 :     put_16aligned_be32(&arp->ar_spa, ip_flow->nw_src);
     152                 :        217 :     arp->ar_tha = eth_addr_zero;
     153                 :        217 :     put_16aligned_be32(&arp->ar_tpa, ip_flow->nw_dst);
     154                 :            : 
     155         [ -  + ]:        217 :     if (ip_flow->vlan_tci & htons(VLAN_CFI)) {
     156                 :          0 :         eth_push_vlan(&packet, htons(ETH_TYPE_VLAN_8021Q), ip_flow->vlan_tci);
     157                 :            :     }
     158                 :            : 
     159                 :            :     /* Compose actions.
     160                 :            :      *
     161                 :            :      * First, copy metadata from 'md' into the packet-out via "set_field"
     162                 :            :      * actions, then add actions from 'userdata'.
     163                 :            :      */
     164                 :            :     uint64_t ofpacts_stub[4096 / 8];
     165                 :        217 :     struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
     166                 :        217 :     enum ofp_version version = rconn_get_version(swconn);
     167                 :            : 
     168                 :        217 :     reload_metadata(&ofpacts, md);
     169                 :        217 :     enum ofperr error = ofpacts_pull_openflow_actions(userdata, userdata->size, version, &ofpacts);
     170         [ -  + ]:        217 :     if (error) {
     171                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     172         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to parse arp actions (%s)",
     173                 :            :                      ofperr_to_string(error));
     174                 :          0 :         goto exit;
     175                 :            :     }
     176                 :            : 
     177                 :        868 :     struct ofputil_packet_out po = {
     178                 :        217 :         .packet = dp_packet_data(&packet),
     179                 :        217 :         .packet_len = dp_packet_size(&packet),
     180                 :            :         .buffer_id = UINT32_MAX,
     181                 :            :         .in_port = OFPP_CONTROLLER,
     182                 :        217 :         .ofpacts = ofpacts.data,
     183                 :        217 :         .ofpacts_len = ofpacts.size,
     184                 :            :     };
     185                 :        217 :     enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
     186                 :        217 :     queue_msg(ofputil_encode_packet_out(&po, proto));
     187                 :            : 
     188                 :            : exit:
     189                 :        217 :     dp_packet_uninit(&packet);
     190                 :        217 :     ofpbuf_uninit(&ofpacts);
     191                 :            : }
     192                 :            : 
     193                 :            : static void
     194                 :          3 : pinctrl_handle_put_dhcp_opts(
     195                 :            :     struct dp_packet *pkt_in, struct ofputil_packet_in *pin,
     196                 :            :     struct ofpbuf *userdata, struct ofpbuf *continuation)
     197                 :            : {
     198                 :          3 :     enum ofp_version version = rconn_get_version(swconn);
     199                 :          3 :     enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
     200                 :          3 :     struct dp_packet *pkt_out_ptr = NULL;
     201                 :          3 :     uint32_t success = 0;
     202                 :            : 
     203                 :            :     /* Parse result field. */
     204                 :            :     const struct mf_field *f;
     205                 :          3 :     enum ofperr ofperr = nx_pull_header(userdata, &f, NULL);
     206         [ -  + ]:          3 :     if (ofperr) {
     207                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     208         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "bad result OXM (%s)", ofperr_to_string(ofperr));
     209                 :          0 :         goto exit;
     210                 :            :     }
     211                 :            : 
     212                 :            :     /* Parse result offset and offer IP. */
     213                 :          3 :     ovs_be32 *ofsp = ofpbuf_try_pull(userdata, sizeof *ofsp);
     214                 :          3 :     ovs_be32 *offer_ip = ofpbuf_try_pull(userdata, sizeof *offer_ip);
     215 [ +  - ][ -  + ]:          3 :     if (!ofsp || !offer_ip) {
     216                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     217         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "offset or offer_ip not present in the userdata");
     218                 :          0 :         goto exit;
     219                 :            :     }
     220                 :            : 
     221                 :            :     /* Check that the result is valid and writable. */
     222                 :          3 :     struct mf_subfield dst = { .field = f, .ofs = ntohl(*ofsp), .n_bits = 1 };
     223                 :          3 :     ofperr = mf_check_dst(&dst, NULL);
     224         [ -  + ]:          3 :     if (ofperr) {
     225                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     226         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "bad result bit (%s)", ofperr_to_string(ofperr));
     227                 :          0 :         goto exit;
     228                 :            :     }
     229                 :            : 
     230         [ -  + ]:          3 :     if (!userdata->size) {
     231                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     232         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "DHCP options not present in the userdata");
     233                 :          0 :         goto exit;
     234                 :            :     }
     235                 :            : 
     236                 :            :     /* Validate the DHCP request packet.
     237                 :            :      * Format of the DHCP packet is
     238                 :            :      * ------------------------------------------------------------------------
     239                 :            :      *| UDP HEADER  | DHCP HEADER  | 4 Byte DHCP Cookie | DHCP OPTIONS(var len)|
     240                 :            :      * ------------------------------------------------------------------------
     241                 :            :      */
     242         [ -  + ]:          3 :     if (dp_packet_l4_size(pkt_in) < (UDP_HEADER_LEN +
     243                 :            :         sizeof (struct dhcp_header) + sizeof(uint32_t) + 3)) {
     244                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     245         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "Invalid or incomplete DHCP packet recieved");
     246                 :          0 :         goto exit;
     247                 :            :     }
     248                 :            : 
     249                 :          3 :     struct dhcp_header const *in_dhcp_data = dp_packet_get_udp_payload(pkt_in);
     250         [ -  + ]:          3 :     if (in_dhcp_data->op != DHCP_OP_REQUEST) {
     251                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     252         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "Invalid opcode in the DHCP packet : %d",
     253                 :            :                      in_dhcp_data->op);
     254                 :          0 :         goto exit;
     255                 :            :     }
     256                 :            : 
     257                 :            :     /* DHCP options follow the DHCP header. The first 4 bytes of the DHCP
     258                 :            :      * options is the DHCP magic cookie followed by the actual DHCP options.
     259                 :            :      */
     260                 :          3 :     const uint8_t *in_dhcp_opt =
     261                 :          3 :         (const uint8_t *)dp_packet_get_udp_payload(pkt_in) +
     262                 :            :         sizeof (struct dhcp_header);
     263                 :            : 
     264                 :          3 :     ovs_be32 magic_cookie = htonl(DHCP_MAGIC_COOKIE);
     265         [ -  + ]:          3 :     if (memcmp(in_dhcp_opt, &magic_cookie, sizeof(ovs_be32))) {
     266                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     267         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "DHCP magic cookie not present in the DHCP packet");
     268                 :          0 :         goto exit;
     269                 :            :     }
     270                 :            : 
     271                 :          3 :     in_dhcp_opt += 4;
     272                 :            :     /* Check that the DHCP Message Type (opt 53) is present or not with
     273                 :            :      * valid values - DHCP_MSG_DISCOVER or DHCP_MSG_REQUEST as the first
     274                 :            :      * DHCP option.
     275                 :            :      */
     276 [ +  - ][ +  - ]:          3 :     if (!(in_dhcp_opt[0] == DHCP_OPT_MSG_TYPE && in_dhcp_opt[1] == 1 && (
                 [ +  + ]
     277         [ +  + ]:          2 :             in_dhcp_opt[2] == DHCP_MSG_DISCOVER ||
     278                 :          2 :             in_dhcp_opt[2] == DHCP_MSG_REQUEST))) {
     279                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     280         [ +  - ]:          1 :         VLOG_WARN_RL(&rl, "Invalid DHCP message type : opt code = %d,"
     281                 :            :                      " opt value = %d", in_dhcp_opt[0], in_dhcp_opt[2]);
     282                 :          1 :         goto exit;
     283                 :            :     }
     284                 :            : 
     285                 :            :     uint8_t msg_type;
     286         [ +  + ]:          2 :     if (in_dhcp_opt[2] == DHCP_MSG_DISCOVER) {
     287                 :          1 :         msg_type = DHCP_MSG_OFFER;
     288                 :            :     } else {
     289                 :          1 :         msg_type = DHCP_MSG_ACK;
     290                 :            :     }
     291                 :            : 
     292                 :            :     /* Frame the DHCP reply packet
     293                 :            :      * Total DHCP options length will be options stored in the userdata +
     294                 :            :      * 16 bytes.
     295                 :            :      *
     296                 :            :      * --------------------------------------------------------------
     297                 :            :      *| 4 Bytes (dhcp cookie) | 3 Bytes (option type) | DHCP options |
     298                 :            :      * --------------------------------------------------------------
     299                 :            :      *| 4 Bytes padding | 1 Byte (option end 0xFF ) | 4 Bytes padding|
     300                 :            :      * --------------------------------------------------------------
     301                 :            :      */
     302                 :          2 :     uint16_t new_l4_size = UDP_HEADER_LEN + DHCP_HEADER_LEN + \
     303                 :          2 :                            userdata->size + 16;
     304                 :          2 :     size_t new_packet_size = pkt_in->l4_ofs + new_l4_size;
     305                 :            : 
     306                 :            :     struct dp_packet pkt_out;
     307                 :          2 :     dp_packet_init(&pkt_out, new_packet_size);
     308                 :          2 :     dp_packet_clear(&pkt_out);
     309                 :          2 :     dp_packet_prealloc_tailroom(&pkt_out, new_packet_size);
     310                 :          2 :     pkt_out_ptr = &pkt_out;
     311                 :            : 
     312                 :            :     /* Copy the L2 and L3 headers from the pkt_in as they would remain same*/
     313                 :          2 :     dp_packet_put(
     314                 :          2 :         &pkt_out, dp_packet_pull(pkt_in, pkt_in->l4_ofs), pkt_in->l4_ofs);
     315                 :            : 
     316                 :          2 :     pkt_out.l2_5_ofs = pkt_in->l2_5_ofs;
     317                 :          2 :     pkt_out.l2_pad_size = pkt_in->l2_pad_size;
     318                 :          2 :     pkt_out.l3_ofs = pkt_in->l3_ofs;
     319                 :          2 :     pkt_out.l4_ofs = pkt_in->l4_ofs;
     320                 :            : 
     321                 :          2 :     struct udp_header *udp = dp_packet_put(
     322                 :          2 :         &pkt_out, dp_packet_pull(pkt_in, UDP_HEADER_LEN), UDP_HEADER_LEN);
     323                 :            : 
     324                 :          2 :     struct dhcp_header *dhcp_data = dp_packet_put(
     325                 :          2 :         &pkt_out, dp_packet_pull(pkt_in, DHCP_HEADER_LEN), DHCP_HEADER_LEN);
     326                 :          2 :     dhcp_data->op = DHCP_OP_REPLY;
     327                 :          2 :     dhcp_data->yiaddr = *offer_ip;
     328                 :          2 :     dp_packet_put(&pkt_out, &magic_cookie, sizeof(ovs_be32));
     329                 :            : 
     330                 :          2 :     uint8_t *out_dhcp_opts = dp_packet_put_zeros(&pkt_out,
     331                 :          2 :                                                  userdata->size + 12);
     332                 :            :     /* DHCP option - type */
     333                 :          2 :     out_dhcp_opts[0] = DHCP_OPT_MSG_TYPE;
     334                 :          2 :     out_dhcp_opts[1] = 1;
     335                 :          2 :     out_dhcp_opts[2] = msg_type;
     336                 :          2 :     out_dhcp_opts += 3;
     337                 :            : 
     338                 :          2 :     memcpy(out_dhcp_opts, userdata->data, userdata->size);
     339                 :          2 :     out_dhcp_opts += userdata->size;
     340                 :            :     /* Padding */
     341                 :          2 :     out_dhcp_opts += 4;
     342                 :            :     /* End */
     343                 :          2 :     out_dhcp_opts[0] = DHCP_OPT_END;
     344                 :            : 
     345                 :          2 :     udp->udp_len = htons(new_l4_size);
     346                 :            : 
     347                 :          2 :     struct ip_header *out_ip = dp_packet_l3(&pkt_out);
     348                 :          2 :     out_ip->ip_tot_len = htons(pkt_out.l4_ofs - pkt_out.l3_ofs + new_l4_size);
     349                 :          2 :     udp->udp_csum = 0;
     350                 :            :     /* Checksum needs to be initialized to zero. */
     351                 :          2 :     out_ip->ip_csum = 0;
     352                 :          2 :     out_ip->ip_csum = csum(out_ip, sizeof *out_ip);
     353                 :            : 
     354                 :          2 :     pin->packet = dp_packet_data(&pkt_out);
     355                 :          2 :     pin->packet_len = dp_packet_size(&pkt_out);
     356                 :            : 
     357                 :          2 :     success = 1;
     358                 :            : exit:
     359         [ +  - ]:          3 :     if (!ofperr) {
     360                 :            :         union mf_subvalue sv;
     361                 :          3 :         sv.u8_val = success;
     362                 :          3 :         mf_write_subfield(&dst, &sv, &pin->flow_metadata);
     363                 :            :     }
     364                 :          3 :     queue_msg(ofputil_encode_resume(pin, continuation, proto));
     365         [ +  + ]:          3 :     if (pkt_out_ptr) {
     366                 :          2 :         dp_packet_uninit(pkt_out_ptr);
     367                 :            :     }
     368                 :          3 : }
     369                 :            : 
     370                 :            : static bool
     371                 :          1 : compose_out_dhcpv6_opts(struct ofpbuf *userdata,
     372                 :            :                         struct ofpbuf *out_dhcpv6_opts, ovs_be32 iaid)
     373                 :            : {
     374         [ +  + ]:          3 :     while (userdata->size) {
     375                 :          2 :         struct dhcp_opt6_header *userdata_opt = ofpbuf_try_pull(
     376                 :            :             userdata, sizeof *userdata_opt);
     377         [ -  + ]:          2 :         if (!userdata_opt) {
     378                 :          0 :             return false;
     379                 :            :         }
     380                 :            : 
     381                 :          2 :         uint8_t *userdata_opt_data = ofpbuf_try_pull(userdata,
     382                 :          2 :                                                      userdata_opt->len);
     383         [ -  + ]:          2 :         if (!userdata_opt_data) {
     384                 :          0 :             return false;
     385                 :            :         }
     386                 :            : 
     387   [ +  +  -  -  :          2 :         switch (userdata_opt->code) {
                      - ]
     388                 :            :         case DHCPV6_OPT_SERVER_ID_CODE:
     389                 :            :         {
     390                 :            :             /* The Server Identifier option carries a DUID
     391                 :            :              * identifying a server between a client and a server.
     392                 :            :              * See RFC 3315 Sec 9 and Sec 22.3.
     393                 :            :              *
     394                 :            :              * We use DUID Based on Link-layer Address [DUID-LL].
     395                 :            :              */
     396                 :            : 
     397                 :          1 :             struct dhcpv6_opt_server_id *opt_server_id = ofpbuf_put_zeros(
     398                 :            :                 out_dhcpv6_opts, sizeof *opt_server_id);
     399                 :            : 
     400                 :          1 :             opt_server_id->opt.code = htons(DHCPV6_OPT_SERVER_ID_CODE);
     401                 :          1 :             opt_server_id->opt.len = htons(userdata_opt->len + 4);
     402                 :          1 :             opt_server_id->duid_type = htons(DHCPV6_DUID_LL);
     403                 :          1 :             opt_server_id->hw_type = htons(DHCPV6_HW_TYPE_ETH);
     404                 :          1 :             memcpy(&opt_server_id->mac, userdata_opt_data,
     405                 :            :                     sizeof(struct eth_addr));
     406                 :          1 :             break;
     407                 :            :         }
     408                 :            : 
     409                 :            :         case DHCPV6_OPT_IA_ADDR_CODE:
     410                 :            :         {
     411         [ -  + ]:          1 :             if (userdata_opt->len != sizeof(struct in6_addr)) {
     412                 :          0 :                 return false;
     413                 :            :             }
     414                 :            : 
     415                 :            :             /* IA Address option is used to specify IPv6 addresses associated
     416                 :            :              * with an IA_NA or IA_TA. The IA Address option must be
     417                 :            :              * encapsulated in the Options field of an IA_NA or IA_TA option.
     418                 :            :              *
     419                 :            :              * We will encapsulate the IA Address within the IA_NA option.
     420                 :            :              * Please see RFC 3315 section 22.5 and 22.6
     421                 :            :              */
     422                 :          1 :             struct dhcpv6_opt_ia_na *opt_ia_na = ofpbuf_put_zeros(
     423                 :            :                 out_dhcpv6_opts, sizeof *opt_ia_na);
     424                 :          1 :             opt_ia_na->opt.code = htons(DHCPV6_OPT_IA_NA_CODE);
     425                 :            :             /* IA_NA length (in bytes)-
     426                 :            :              *  IAID - 4
     427                 :            :              *  T1   - 4
     428                 :            :              *  T2   - 4
     429                 :            :              *  IA Address - sizeof(struct dhcpv6_opt_ia_addr)
     430                 :            :              */
     431                 :          1 :             opt_ia_na->opt.len = htons(12 + sizeof(struct dhcpv6_opt_ia_addr));
     432                 :          1 :             opt_ia_na->iaid = iaid;
     433                 :            :             /* Set the lifetime of the address(es) to infinity */
     434                 :          1 :             opt_ia_na->t1 = OVS_BE32_MAX;
     435                 :          1 :             opt_ia_na->t2 = OVS_BE32_MAX;
     436                 :            : 
     437                 :          1 :             struct dhcpv6_opt_ia_addr *opt_ia_addr = ofpbuf_put_zeros(
     438                 :            :                 out_dhcpv6_opts, sizeof *opt_ia_addr);
     439                 :          1 :             opt_ia_addr->opt.code = htons(DHCPV6_OPT_IA_ADDR_CODE);
     440                 :          1 :             opt_ia_addr->opt.len = htons(userdata_opt->len + 8);
     441                 :          1 :             memcpy(opt_ia_addr->ipv6.s6_addr, userdata_opt_data,
     442                 :          1 :                    userdata_opt->len);
     443                 :          1 :             opt_ia_addr->t1 = OVS_BE32_MAX;
     444                 :          1 :             opt_ia_addr->t2 = OVS_BE32_MAX;
     445                 :          1 :             break;
     446                 :            :         }
     447                 :            : 
     448                 :            :         case DHCPV6_OPT_DNS_SERVER_CODE:
     449                 :            :         {
     450                 :          0 :             struct dhcpv6_opt_header *opt_dns = ofpbuf_put_zeros(
     451                 :            :                 out_dhcpv6_opts, sizeof *opt_dns);
     452                 :          0 :             opt_dns->code = htons(DHCPV6_OPT_DNS_SERVER_CODE);
     453                 :          0 :             opt_dns->len = htons(userdata_opt->len);
     454                 :          0 :             ofpbuf_put(out_dhcpv6_opts, userdata_opt_data, userdata_opt->len);
     455                 :          0 :             break;
     456                 :            :         }
     457                 :            : 
     458                 :            :         case DHCPV6_OPT_DOMAIN_SEARCH_CODE:
     459                 :            :         {
     460                 :          0 :             struct dhcpv6_opt_header *opt_dsl = ofpbuf_put_zeros(
     461                 :            :                 out_dhcpv6_opts, sizeof *opt_dsl);
     462                 :          0 :             opt_dsl->code = htons(DHCPV6_OPT_DOMAIN_SEARCH_CODE);
     463                 :          0 :             opt_dsl->len = htons(userdata_opt->len + 2);
     464                 :          0 :             uint8_t *data = ofpbuf_put_zeros(out_dhcpv6_opts,
     465                 :          0 :                                               userdata_opt->len + 2);
     466                 :          0 :             *data = userdata_opt->len;
     467                 :          0 :             memcpy(data + 1, userdata_opt_data, userdata_opt->len);
     468                 :          0 :             break;
     469                 :            :         }
     470                 :            : 
     471                 :            :         default:
     472                 :          0 :             return false;
     473                 :            :         }
     474                 :            :     }
     475                 :          1 :     return true;
     476                 :            : }
     477                 :            : 
     478                 :            : static void
     479                 :          2 : pinctrl_handle_put_dhcpv6_opts(
     480                 :            :     struct dp_packet *pkt_in, struct ofputil_packet_in *pin,
     481                 :            :     struct ofpbuf *userdata, struct ofpbuf *continuation OVS_UNUSED)
     482                 :            : {
     483                 :            :     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     484                 :          2 :     enum ofp_version version = rconn_get_version(swconn);
     485                 :          2 :     enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
     486                 :          2 :     struct dp_packet *pkt_out_ptr = NULL;
     487                 :          2 :     uint32_t success = 0;
     488                 :            : 
     489                 :            :     /* Parse result field. */
     490                 :            :     const struct mf_field *f;
     491                 :          2 :     enum ofperr ofperr = nx_pull_header(userdata, &f, NULL);
     492         [ -  + ]:          2 :     if (ofperr) {
     493         [ #  # ]:          0 :        VLOG_WARN_RL(&rl, "bad result OXM (%s)", ofperr_to_string(ofperr));
     494                 :          0 :        goto exit;
     495                 :            :     }
     496                 :            : 
     497                 :            :     /* Parse result offset. */
     498                 :          2 :     ovs_be32 *ofsp = ofpbuf_try_pull(userdata, sizeof *ofsp);
     499         [ -  + ]:          2 :     if (!ofsp) {
     500         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "offset not present in the userdata");
     501                 :          0 :         goto exit;
     502                 :            :     }
     503                 :            : 
     504                 :            :     /* Check that the result is valid and writable. */
     505                 :          2 :     struct mf_subfield dst = { .field = f, .ofs = ntohl(*ofsp), .n_bits = 1 };
     506                 :          2 :     ofperr = mf_check_dst(&dst, NULL);
     507         [ -  + ]:          2 :     if (ofperr) {
     508         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "bad result bit (%s)", ofperr_to_string(ofperr));
     509                 :          0 :         goto exit;
     510                 :            :     }
     511                 :            : 
     512         [ -  + ]:          2 :     if (!userdata->size) {
     513         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "DHCPv6 options not present in the userdata");
     514                 :          0 :         goto exit;
     515                 :            :     }
     516                 :            : 
     517                 :          2 :     struct udp_header *in_udp = dp_packet_l4(pkt_in);
     518                 :          2 :     const uint8_t *in_dhcpv6_data = dp_packet_get_udp_payload(pkt_in);
     519                 :            :     uint8_t out_dhcpv6_msg_type;
     520      [ +  -  + ]:          2 :     switch(*in_dhcpv6_data) {
     521                 :            :     case DHCPV6_MSG_TYPE_SOLICIT:
     522                 :          1 :         out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_ADVT;
     523                 :          1 :         break;
     524                 :            : 
     525                 :            :     case DHCPV6_MSG_TYPE_REQUEST:
     526                 :            :     case DHCPV6_MSG_TYPE_CONFIRM:
     527                 :            :     case DHCPV6_MSG_TYPE_DECLINE:
     528                 :          0 :         out_dhcpv6_msg_type = DHCPV6_MSG_TYPE_REPLY;
     529                 :          0 :         break;
     530                 :            : 
     531                 :            :     default:
     532                 :            :         /* Invalid or unsupported DHCPv6 message type */
     533                 :          1 :         goto exit;
     534                 :            :     }
     535                 :            : 
     536                 :            :     /* Skip 4 bytes (message type (1 byte) + transaction ID (3 bytes). */
     537                 :          1 :     in_dhcpv6_data += 4;
     538                 :            :     /* We need to extract IAID from the IA-NA option of the client's DHCPv6
     539                 :            :      * solicit/request/confirm packet and copy the same IAID in the Server's
     540                 :            :      * response. */
     541                 :          1 :     ovs_be32 iaid = 0;
     542                 :          1 :     struct dhcpv6_opt_header const *in_opt_client_id = NULL;
     543                 :          1 :     size_t udp_len = ntohs(in_udp->udp_len);
     544                 :          1 :     size_t l4_len = dp_packet_l4_size(pkt_in);
     545                 :          1 :     uint8_t *end = (uint8_t *)in_udp + MIN(udp_len, l4_len);
     546         [ +  + ]:          3 :     while (in_dhcpv6_data < end) {
     547                 :          2 :         struct dhcpv6_opt_header const *in_opt =
     548                 :            :              (struct dhcpv6_opt_header *)in_dhcpv6_data;
     549      [ +  +  - ]:          2 :         switch(ntohs(in_opt->code)) {
     550                 :            :         case DHCPV6_OPT_IA_NA_CODE:
     551                 :            :         {
     552                 :          1 :             struct dhcpv6_opt_ia_na *opt_ia_na = (
     553                 :            :                 struct dhcpv6_opt_ia_na *)in_opt;
     554                 :          1 :             iaid = opt_ia_na->iaid;
     555                 :          1 :             break;
     556                 :            :         }
     557                 :            : 
     558                 :            :         case DHCPV6_OPT_CLIENT_ID_CODE:
     559                 :          1 :             in_opt_client_id = in_opt;
     560                 :          1 :             break;
     561                 :            : 
     562                 :            :         default:
     563                 :          0 :             break;
     564                 :            :         }
     565                 :          2 :         in_dhcpv6_data += sizeof *in_opt + ntohs(in_opt->len);
     566                 :            :     }
     567                 :            : 
     568         [ -  + ]:          1 :     if (!in_opt_client_id) {
     569         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "DHCPv6 option - Client id not present in the "
     570                 :            :                      " DHCPv6 packet");
     571                 :          0 :         goto exit;
     572                 :            :     }
     573                 :            : 
     574         [ -  + ]:          1 :     if (!iaid) {
     575         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "DHCPv6 option - IA NA not present in the "
     576                 :            :                      " DHCPv6 packet");
     577                 :          0 :         goto exit;
     578                 :            :     }
     579                 :            : 
     580                 :            :     uint64_t out_ofpacts_dhcpv6_opts_stub[256 / 8];
     581                 :          1 :     struct ofpbuf out_dhcpv6_opts =
     582                 :            :         OFPBUF_STUB_INITIALIZER(out_ofpacts_dhcpv6_opts_stub);
     583                 :            : 
     584         [ -  + ]:          1 :     if (!compose_out_dhcpv6_opts(userdata, &out_dhcpv6_opts, iaid)) {
     585         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "Invalid userdata");
     586                 :          0 :         goto exit;
     587                 :            :     }
     588                 :            : 
     589                 :          1 :     uint16_t new_l4_size
     590                 :            :         = (UDP_HEADER_LEN + 4 + sizeof *in_opt_client_id +
     591                 :          1 :            ntohs(in_opt_client_id->len) + out_dhcpv6_opts.size);
     592                 :          1 :     size_t new_packet_size = pkt_in->l4_ofs + new_l4_size;
     593                 :            : 
     594                 :            :     struct dp_packet pkt_out;
     595                 :          1 :     dp_packet_init(&pkt_out, new_packet_size);
     596                 :          1 :     dp_packet_clear(&pkt_out);
     597                 :          1 :     dp_packet_prealloc_tailroom(&pkt_out, new_packet_size);
     598                 :          1 :     pkt_out_ptr = &pkt_out;
     599                 :            : 
     600                 :            :     /* Copy L2 and L3 headers from pkt_in. */
     601                 :          1 :     dp_packet_put(&pkt_out, dp_packet_pull(pkt_in, pkt_in->l4_ofs),
     602                 :          1 :                   pkt_in->l4_ofs);
     603                 :            : 
     604                 :          1 :     pkt_out.l2_5_ofs = pkt_in->l2_5_ofs;
     605                 :          1 :     pkt_out.l2_pad_size = pkt_in->l2_pad_size;
     606                 :          1 :     pkt_out.l3_ofs = pkt_in->l3_ofs;
     607                 :          1 :     pkt_out.l4_ofs = pkt_in->l4_ofs;
     608                 :            : 
     609                 :            :     /* Pull the DHCPv6 message type and transaction id from the pkt_in.
     610                 :            :      * Need to preserve the transaction id in the DHCPv6 reply packet. */
     611                 :          1 :     struct udp_header *out_udp = dp_packet_put(
     612                 :          1 :         &pkt_out, dp_packet_pull(pkt_in, UDP_HEADER_LEN), UDP_HEADER_LEN);
     613                 :          1 :     uint8_t *out_dhcpv6 = dp_packet_put(&pkt_out, dp_packet_pull(pkt_in, 4), 4);
     614                 :            : 
     615                 :            :     /* Set the proper DHCPv6 message type. */
     616                 :          1 :     *out_dhcpv6 = out_dhcpv6_msg_type;
     617                 :            : 
     618                 :            :     /* Copy the Client Identifier. */
     619                 :          1 :     dp_packet_put(&pkt_out, in_opt_client_id,
     620                 :          1 :                   sizeof *in_opt_client_id + ntohs(in_opt_client_id->len));
     621                 :            : 
     622                 :            :     /* Copy the DHCPv6 Options. */
     623                 :          1 :     dp_packet_put(&pkt_out, out_dhcpv6_opts.data, out_dhcpv6_opts.size);
     624                 :          1 :     out_udp->udp_len = htons(new_l4_size);
     625                 :          1 :     out_udp->udp_csum = 0;
     626                 :            : 
     627                 :          1 :     struct ovs_16aligned_ip6_hdr *out_ip6 = dp_packet_l3(&pkt_out);
     628                 :          1 :     out_ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = out_udp->udp_len;
     629                 :            : 
     630                 :            :     uint32_t csum;
     631                 :          1 :     csum = packet_csum_pseudoheader6(dp_packet_l3(&pkt_out));
     632                 :          2 :     csum = csum_continue(csum, out_udp, dp_packet_size(&pkt_out) -
     633                 :          2 :                          ((const unsigned char *)out_udp -
     634                 :          1 :                          (const unsigned char *)dp_packet_l2(&pkt_out)));
     635                 :          1 :     out_udp->udp_csum = csum_finish(csum);
     636         [ -  + ]:          1 :     if (!out_udp->udp_csum) {
     637                 :          0 :         out_udp->udp_csum = htons(0xffff);
     638                 :            :     }
     639                 :            : 
     640                 :          1 :     pin->packet = dp_packet_data(&pkt_out);
     641                 :          1 :     pin->packet_len = dp_packet_size(&pkt_out);
     642                 :          1 :     ofpbuf_uninit(&out_dhcpv6_opts);
     643                 :          1 :     success = 1;
     644                 :            : exit:
     645         [ +  - ]:          2 :     if (!ofperr) {
     646                 :            :         union mf_subvalue sv;
     647                 :          2 :         sv.u8_val = success;
     648                 :          2 :         mf_write_subfield(&dst, &sv, &pin->flow_metadata);
     649                 :            :     }
     650                 :          2 :     queue_msg(ofputil_encode_resume(pin, continuation, proto));
     651                 :          2 :     dp_packet_uninit(pkt_out_ptr);
     652                 :          2 : }
     653                 :            : 
     654                 :            : static void
     655                 :        453 : process_packet_in(const struct ofp_header *msg)
     656                 :            : {
     657                 :            :     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     658                 :            : 
     659                 :            :     struct ofputil_packet_in pin;
     660                 :            :     struct ofpbuf continuation;
     661                 :        453 :     enum ofperr error = ofputil_decode_packet_in(msg, true, &pin,
     662                 :            :                                                  NULL, NULL, &continuation);
     663                 :            : 
     664         [ -  + ]:        453 :     if (error) {
     665         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "error decoding packet-in: %s",
     666                 :            :                      ofperr_to_string(error));
     667                 :          0 :         return;
     668                 :            :     }
     669         [ -  + ]:        453 :     if (pin.reason != OFPR_ACTION) {
     670                 :          0 :         return;
     671                 :            :     }
     672                 :            : 
     673                 :        453 :     struct ofpbuf userdata = ofpbuf_const_initializer(pin.userdata,
     674                 :            :                                                       pin.userdata_len);
     675                 :        453 :     const struct action_header *ah = ofpbuf_pull(&userdata, sizeof *ah);
     676         [ -  + ]:        453 :     if (!ah) {
     677         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "packet-in userdata lacks action header");
     678                 :          0 :         return;
     679                 :            :     }
     680                 :            : 
     681                 :            :     struct dp_packet packet;
     682                 :        453 :     dp_packet_use_const(&packet, pin.packet, pin.packet_len);
     683                 :            :     struct flow headers;
     684                 :        453 :     flow_extract(&packet, &headers);
     685                 :            : 
     686   [ +  +  +  +  :        453 :     switch (ntohl(ah->opcode)) {
                +  +  - ]
     687                 :            :     case ACTION_OPCODE_ARP:
     688                 :        217 :         pinctrl_handle_arp(&headers, &pin.flow_metadata, &userdata);
     689                 :        217 :         break;
     690                 :            : 
     691                 :            :     case ACTION_OPCODE_PUT_ARP:
     692                 :        216 :         pinctrl_handle_put_mac_binding(&pin.flow_metadata.flow, &headers,
     693                 :            :                                        true);
     694                 :        216 :         break;
     695                 :            : 
     696                 :            :     case ACTION_OPCODE_PUT_DHCP_OPTS:
     697                 :          3 :         pinctrl_handle_put_dhcp_opts(&packet, &pin, &userdata, &continuation);
     698                 :          3 :         break;
     699                 :            : 
     700                 :            :     case ACTION_OPCODE_ND_NA:
     701                 :          1 :         pinctrl_handle_nd_na(&headers, &pin.flow_metadata, &userdata);
     702                 :          1 :         break;
     703                 :            : 
     704                 :            :     case ACTION_OPCODE_PUT_ND:
     705                 :         14 :         pinctrl_handle_put_mac_binding(&pin.flow_metadata.flow, &headers,
     706                 :            :                                        false);
     707                 :         14 :         break;
     708                 :            : 
     709                 :            :     case ACTION_OPCODE_PUT_DHCPV6_OPTS:
     710                 :          2 :         pinctrl_handle_put_dhcpv6_opts(&packet, &pin, &userdata,
     711                 :            :                                        &continuation);
     712                 :          2 :         break;
     713                 :            : 
     714                 :            :     default:
     715         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "unrecognized packet-in opcode %"PRIu32,
     716                 :            :                      ntohl(ah->opcode));
     717                 :        453 :         break;
     718                 :            :     }
     719                 :            : }
     720                 :            : 
     721                 :            : static void
     722                 :        910 : pinctrl_recv(const struct ofp_header *oh, enum ofptype type)
     723                 :            : {
     724         [ +  + ]:        910 :     if (type == OFPTYPE_ECHO_REQUEST) {
     725                 :          6 :         queue_msg(make_echo_reply(oh));
     726         [ +  + ]:        904 :     } else if (type == OFPTYPE_GET_CONFIG_REPLY) {
     727                 :            :         /* Enable asynchronous messages (see "Asynchronous Messages" in
     728                 :            :          * DESIGN.md for more information). */
     729                 :            :         struct ofputil_switch_config config;
     730                 :            : 
     731                 :         46 :         ofputil_decode_get_config_reply(oh, &config);
     732                 :         46 :         config.miss_send_len = UINT16_MAX;
     733                 :         46 :         set_switch_config(swconn, &config);
     734         [ +  + ]:        858 :     } else if (type == OFPTYPE_PACKET_IN) {
     735                 :        453 :         process_packet_in(oh);
     736 [ +  - ][ +  - ]:        405 :     } else if (type != OFPTYPE_ECHO_REPLY && type != OFPTYPE_BARRIER_REPLY) {
     737         [ -  + ]:        405 :         if (VLOG_IS_DBG_ENABLED()) {
     738                 :            :             static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(30, 300);
     739                 :            : 
     740                 :          0 :             char *s = ofp_to_string(oh, ntohs(oh->length), 2);
     741                 :            : 
     742         [ #  # ]:          0 :             VLOG_DBG_RL(&rl, "OpenFlow packet ignored: %s", s);
     743                 :          0 :             free(s);
     744                 :            :         }
     745                 :            :     }
     746                 :        910 : }
     747                 :            : 
     748                 :            : void
     749                 :       3167 : pinctrl_run(struct controller_ctx *ctx, const struct lport_index *lports,
     750                 :            :             const struct ovsrec_bridge *br_int,
     751                 :            :             const char *chassis_id,
     752                 :            :             struct hmap *local_datapaths)
     753                 :            : {
     754                 :       3167 :     char *target = xasprintf("unix:%s/%s.mgmt", ovs_rundir(), br_int->name);
     755         [ +  + ]:       3167 :     if (strcmp(target, rconn_get_target(swconn))) {
     756         [ +  - ]:         44 :         VLOG_INFO("%s: connecting to switch", target);
     757                 :         44 :         rconn_connect(swconn, target, target);
     758                 :            :     }
     759                 :       3167 :     free(target);
     760                 :            : 
     761                 :       3167 :     rconn_run(swconn);
     762                 :            : 
     763         [ +  + ]:       3167 :     if (rconn_is_connected(swconn)) {
     764         [ +  + ]:       3070 :         if (conn_seq_no != rconn_get_connection_seqno(swconn)) {
     765                 :         46 :             pinctrl_setup(swconn);
     766                 :         46 :             conn_seq_no = rconn_get_connection_seqno(swconn);
     767                 :         46 :             flush_put_mac_bindings();
     768                 :            :         }
     769                 :            : 
     770                 :            :         /* Process a limited number of messages per call. */
     771         [ +  - ]:       3980 :         for (int i = 0; i < 50; i++) {
     772                 :       3980 :             struct ofpbuf *msg = rconn_recv(swconn);
     773         [ +  + ]:       3980 :             if (!msg) {
     774                 :       3070 :                 break;
     775                 :            :             }
     776                 :            : 
     777                 :        910 :             const struct ofp_header *oh = msg->data;
     778                 :            :             enum ofptype type;
     779                 :            : 
     780                 :        910 :             ofptype_decode(&type, oh);
     781                 :        910 :             pinctrl_recv(oh, type);
     782                 :        910 :             ofpbuf_delete(msg);
     783                 :            :         }
     784                 :            :     }
     785                 :            : 
     786                 :       3167 :     run_put_mac_bindings(ctx, lports);
     787                 :       3167 :     send_garp_run(br_int, chassis_id, lports, local_datapaths);
     788                 :       3167 : }
     789                 :            : 
     790                 :            : void
     791                 :       3167 : pinctrl_wait(struct controller_ctx *ctx)
     792                 :            : {
     793                 :       3167 :     wait_put_mac_bindings(ctx);
     794                 :       3167 :     rconn_run_wait(swconn);
     795                 :       3167 :     rconn_recv_wait(swconn);
     796                 :       3167 :     send_garp_wait();
     797                 :       3167 : }
     798                 :            : 
     799                 :            : void
     800                 :         44 : pinctrl_destroy(void)
     801                 :            : {
     802                 :         44 :     rconn_destroy(swconn);
     803                 :         44 :     destroy_put_mac_bindings();
     804                 :         44 :     destroy_send_garps();
     805                 :         44 : }
     806                 :            : 
     807                 :            : /* Implementation of the "put_arp" and "put_nd" OVN actions.  These
     808                 :            :  * actions send a packet to ovn-controller, using the flow as an API
     809                 :            :  * (see actions.h for details).  This code implements the actions by
     810                 :            :  * updating the MAC_Binding table in the southbound database.
     811                 :            :  *
     812                 :            :  * This code could be a lot simpler if the database could always be updated,
     813                 :            :  * but in fact we can only update it when ctx->ovnsb_idl_txn is nonnull.  Thus,
     814                 :            :  * we buffer up a few put_mac_bindings (but we don't keep them longer
     815                 :            :  * than 1 second) and apply them whenever a database transaction is
     816                 :            :  * available. */
     817                 :            : 
     818                 :            : /* Buffered "put_mac_binding" operation. */
     819                 :            : struct put_mac_binding {
     820                 :            :     struct hmap_node hmap_node; /* In 'put_mac_bindings'. */
     821                 :            : 
     822                 :            :     long long int timestamp;    /* In milliseconds. */
     823                 :            : 
     824                 :            :     /* Key. */
     825                 :            :     uint32_t dp_key;
     826                 :            :     uint32_t port_key;
     827                 :            :     char ip_s[INET6_ADDRSTRLEN + 1];
     828                 :            : 
     829                 :            :     /* Value. */
     830                 :            :     struct eth_addr mac;
     831                 :            : };
     832                 :            : 
     833                 :            : /* Contains "struct put_mac_binding"s. */
     834                 :            : static struct hmap put_mac_bindings;
     835                 :            : 
     836                 :            : static void
     837                 :         44 : init_put_mac_bindings(void)
     838                 :            : {
     839                 :         44 :     hmap_init(&put_mac_bindings);
     840                 :         44 : }
     841                 :            : 
     842                 :            : static void
     843                 :         44 : destroy_put_mac_bindings(void)
     844                 :            : {
     845                 :         44 :     flush_put_mac_bindings();
     846                 :         44 :     hmap_destroy(&put_mac_bindings);
     847                 :         44 : }
     848                 :            : 
     849                 :            : static struct put_mac_binding *
     850                 :        230 : pinctrl_find_put_mac_binding(uint32_t dp_key, uint32_t port_key,
     851                 :            :                              const char *ip_s, uint32_t hash)
     852                 :            : {
     853                 :            :     struct put_mac_binding *pa;
     854 [ -  + ][ -  + ]:        230 :     HMAP_FOR_EACH_WITH_HASH (pa, hmap_node, hash, &put_mac_bindings) {
     855         [ #  # ]:          0 :         if (pa->dp_key == dp_key
     856         [ #  # ]:          0 :             && pa->port_key == port_key
     857         [ #  # ]:          0 :             && !strcmp(pa->ip_s, ip_s)) {
     858                 :          0 :             return pa;
     859                 :            :         }
     860                 :            :     }
     861                 :        230 :     return NULL;
     862                 :            : }
     863                 :            : 
     864                 :            : static void
     865                 :        230 : pinctrl_handle_put_mac_binding(const struct flow *md,
     866                 :            :                                const struct flow *headers, bool is_arp)
     867                 :            : {
     868                 :        230 :     uint32_t dp_key = ntohll(md->metadata);
     869                 :        230 :     uint32_t port_key = md->regs[MFF_LOG_INPORT - MFF_REG0];
     870                 :            :     char ip_s[INET6_ADDRSTRLEN];
     871                 :            : 
     872         [ +  + ]:        230 :     if (is_arp) {
     873                 :        216 :         ovs_be32 ip = htonl(md->regs[0]);
     874                 :        216 :         inet_ntop(AF_INET, &ip, ip_s, sizeof(ip_s));
     875                 :            :     } else {
     876                 :         14 :         ovs_be128 ip6 = hton128(flow_get_xxreg(md, 0));
     877                 :         14 :         inet_ntop(AF_INET6, &ip6, ip_s, sizeof(ip_s));
     878                 :            :     }
     879                 :        230 :     uint32_t hash = hash_string(ip_s, hash_2words(dp_key, port_key));
     880                 :        230 :     struct put_mac_binding *pmb
     881                 :            :         = pinctrl_find_put_mac_binding(dp_key, port_key, ip_s, hash);
     882         [ +  - ]:        230 :     if (!pmb) {
     883         [ -  + ]:        230 :         if (hmap_count(&put_mac_bindings) >= 1000) {
     884                 :          0 :             COVERAGE_INC(pinctrl_drop_put_mac_binding);
     885                 :          0 :             return;
     886                 :            :         }
     887                 :            : 
     888                 :        230 :         pmb = xmalloc(sizeof *pmb);
     889                 :        230 :         hmap_insert(&put_mac_bindings, &pmb->hmap_node, hash);
     890                 :        230 :         pmb->dp_key = dp_key;
     891                 :        230 :         pmb->port_key = port_key;
     892                 :        230 :         ovs_strlcpy(pmb->ip_s, ip_s, sizeof pmb->ip_s);
     893                 :            :     }
     894                 :        230 :     pmb->timestamp = time_msec();
     895                 :        230 :     pmb->mac = headers->dl_src;
     896                 :            : }
     897                 :            : 
     898                 :            : static void
     899                 :        230 : run_put_mac_binding(struct controller_ctx *ctx,
     900                 :            :                     const struct lport_index *lports,
     901                 :            :                     const struct put_mac_binding *pmb)
     902                 :            : {
     903         [ -  + ]:        230 :     if (time_msec() > pmb->timestamp + 1000) {
     904                 :          4 :         return;
     905                 :            :     }
     906                 :            : 
     907                 :            :     /* Convert logical datapath and logical port key into lport. */
     908                 :        230 :     const struct sbrec_port_binding *pb
     909                 :        230 :         = lport_lookup_by_key(lports, pmb->dp_key, pmb->port_key);
     910         [ -  + ]:        230 :     if (!pb) {
     911                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
     912                 :            : 
     913         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "unknown logical port with datapath %"PRIu32" "
     914                 :            :                      "and port %"PRIu32, pmb->dp_key, pmb->port_key);
     915                 :          0 :         return;
     916                 :            :     }
     917                 :            : 
     918                 :            :     /* Convert ethernet argument to string form for database. */
     919                 :            :     char mac_string[ETH_ADDR_STRLEN + 1];
     920                 :       1380 :     snprintf(mac_string, sizeof mac_string,
     921                 :       1380 :              ETH_ADDR_FMT, ETH_ADDR_ARGS(pmb->mac));
     922                 :            : 
     923                 :            :     /* Check for an update an existing IP-MAC binding for this logical
     924                 :            :      * port.
     925                 :            :      *
     926                 :            :      * XXX This is not very efficient. */
     927                 :            :     const struct sbrec_mac_binding *b;
     928         [ +  + ]:      23263 :     SBREC_MAC_BINDING_FOR_EACH (b, ctx->ovnsb_idl) {
     929         [ +  + ]:      23037 :         if (!strcmp(b->logical_port, pb->logical_port)
     930         [ +  + ]:       2488 :             && !strcmp(b->ip, pmb->ip_s)) {
     931         [ -  + ]:          4 :             if (strcmp(b->mac, mac_string)) {
     932                 :          0 :                 sbrec_mac_binding_set_mac(b, mac_string);
     933                 :            :             }
     934                 :          4 :             return;
     935                 :            :         }
     936                 :            :     }
     937                 :            : 
     938                 :            :     /* Add new IP-MAC binding for this logical port. */
     939                 :        226 :     b = sbrec_mac_binding_insert(ctx->ovnsb_idl_txn);
     940                 :        226 :     sbrec_mac_binding_set_logical_port(b, pb->logical_port);
     941                 :        226 :     sbrec_mac_binding_set_ip(b, pmb->ip_s);
     942                 :        226 :     sbrec_mac_binding_set_mac(b, mac_string);
     943                 :        226 :     sbrec_mac_binding_set_datapath(b, pb->datapath);
     944                 :            : }
     945                 :            : 
     946                 :            : static void
     947                 :       3167 : run_put_mac_bindings(struct controller_ctx *ctx,
     948                 :            :                      const struct lport_index *lports)
     949                 :            : {
     950         [ +  + ]:       3167 :     if (!ctx->ovnsb_idl_txn) {
     951                 :        497 :         return;
     952                 :            :     }
     953                 :            : 
     954                 :            :     const struct put_mac_binding *pmb;
     955 [ +  + ][ -  + ]:       2900 :     HMAP_FOR_EACH (pmb, hmap_node, &put_mac_bindings) {
     956                 :        230 :         run_put_mac_binding(ctx, lports, pmb);
     957                 :            :     }
     958                 :       2670 :     flush_put_mac_bindings();
     959                 :            : }
     960                 :            : 
     961                 :            : static void
     962                 :       3167 : wait_put_mac_bindings(struct controller_ctx *ctx)
     963                 :            : {
     964 [ +  + ][ -  + ]:       3167 :     if (ctx->ovnsb_idl_txn && !hmap_is_empty(&put_mac_bindings)) {
     965                 :          0 :         poll_immediate_wake();
     966                 :            :     }
     967                 :       3167 : }
     968                 :            : 
     969                 :            : static void
     970                 :       2760 : flush_put_mac_bindings(void)
     971                 :            : {
     972                 :            :     struct put_mac_binding *pmb;
     973 [ +  + ][ -  + ]:       2990 :     HMAP_FOR_EACH_POP (pmb, hmap_node, &put_mac_bindings) {
                 [ +  + ]
     974                 :        230 :         free(pmb);
     975                 :            :     }
     976                 :       2760 : }
     977                 :            : 
     978                 :            : /*
     979                 :            :  * Send gratuitous ARP for vif on localnet.
     980                 :            :  *
     981                 :            :  * When a new vif on localnet is added, gratuitous ARPs are sent announcing
     982                 :            :  * the port's mac,ip mapping.  On localnet, such announcements are needed for
     983                 :            :  * switches and routers on the broadcast segment to update their port-mac
     984                 :            :  * and ARP tables.
     985                 :            :  */
     986                 :            : struct garp_data {
     987                 :            :     struct eth_addr ea;          /* Ethernet address of port. */
     988                 :            :     ovs_be32 ipv4;               /* Ipv4 address of port. */
     989                 :            :     long long int announce_time; /* Next announcement in ms. */
     990                 :            :     int backoff;                 /* Backoff for the next announcement. */
     991                 :            :     ofp_port_t ofport;           /* ofport used to output this GARP. */
     992                 :            : };
     993                 :            : 
     994                 :            : /* Contains GARPs to be sent. */
     995                 :            : static struct shash send_garp_data;
     996                 :            : 
     997                 :            : /* Next GARP announcement in ms. */
     998                 :            : static long long int send_garp_time;
     999                 :            : 
    1000                 :            : static void
    1001                 :         44 : init_send_garps(void)
    1002                 :            : {
    1003                 :         44 :     shash_init(&send_garp_data);
    1004                 :         44 :     send_garp_time = LLONG_MAX;
    1005                 :         44 : }
    1006                 :            : 
    1007                 :            : static void
    1008                 :         44 : destroy_send_garps(void)
    1009                 :            : {
    1010                 :         44 :     shash_destroy_free_data(&send_garp_data);
    1011                 :         44 : }
    1012                 :            : 
    1013                 :            : static void
    1014                 :          3 : add_garp(const char *name, ofp_port_t ofport,
    1015                 :            :          const struct eth_addr ea, ovs_be32 ip)
    1016                 :            : {
    1017                 :          3 :     struct garp_data *garp = xmalloc(sizeof *garp);
    1018                 :          3 :     garp->ea = ea;
    1019                 :          3 :     garp->ipv4 = ip;
    1020                 :          3 :     garp->announce_time = time_msec() + 1000;
    1021                 :          3 :     garp->backoff = 1;
    1022                 :          3 :     garp->ofport = ofport;
    1023                 :          3 :     shash_add(&send_garp_data, name, garp);
    1024                 :          3 : }
    1025                 :            : 
    1026                 :            : /* Add or update a vif for which GARPs need to be announced. */
    1027                 :            : static void
    1028                 :       1194 : send_garp_update(const struct sbrec_port_binding *binding_rec,
    1029                 :            :                  struct simap *localnet_ofports, struct hmap *local_datapaths,
    1030                 :            :                  struct shash *nat_addresses)
    1031                 :            : {
    1032                 :            :     /* Find the localnet ofport to send this GARP. */
    1033                 :       1194 :     struct local_datapath *ld
    1034                 :       1194 :         = get_local_datapath(local_datapaths,
    1035                 :       1194 :                              binding_rec->datapath->tunnel_key);
    1036 [ +  + ][ +  + ]:       1194 :     if (!ld || !ld->localnet_port) {
    1037                 :        635 :         return;
    1038                 :            :     }
    1039                 :        559 :     ofp_port_t ofport = u16_to_ofp(simap_get(localnet_ofports,
    1040                 :        559 :                                              ld->localnet_port->logical_port));
    1041                 :            : 
    1042                 :        559 :     volatile struct garp_data *garp = NULL;
    1043                 :            :     /* Update GARP for NAT IP if it exists. */
    1044         [ +  + ]:        559 :     if (!strcmp(binding_rec->type, "l3gateway")) {
    1045                 :          8 :         struct lport_addresses *laddrs = NULL;
    1046                 :          8 :         laddrs = shash_find_data(nat_addresses, binding_rec->logical_port);
    1047         [ -  + ]:          8 :         if (!laddrs) {
    1048                 :          0 :             return;
    1049                 :            :         }
    1050                 :            :         int i;
    1051         [ +  + ]:         16 :         for (i = 0; i < laddrs->n_ipv4_addrs; i++) {
    1052                 :          8 :             char *name = xasprintf("%s-%s", binding_rec->logical_port,
    1053                 :          8 :                                             laddrs->ipv4_addrs[i].addr_s);
    1054                 :          8 :             garp = shash_find_data(&send_garp_data, name);
    1055         [ +  + ]:          8 :             if (garp) {
    1056                 :          7 :                 garp->ofport = ofport;
    1057                 :            :             } else {
    1058                 :          1 :                 add_garp(name, ofport, laddrs->ea, laddrs->ipv4_addrs[i].addr);
    1059                 :            :             }
    1060                 :          8 :             free(name);
    1061                 :            :         }
    1062                 :          8 :         return;
    1063                 :            :     }
    1064                 :            : 
    1065                 :            :     /* Update GARP for vif if it exists. */
    1066                 :        551 :     garp = shash_find_data(&send_garp_data, binding_rec->logical_port);
    1067         [ +  + ]:        551 :     if (garp) {
    1068                 :         10 :         garp->ofport = ofport;
    1069                 :         10 :         return;
    1070                 :            :     }
    1071                 :            : 
    1072                 :            :     /* Add GARP for new vif. */
    1073                 :            :     int i;
    1074         [ +  + ]:       1031 :     for (i = 0; i < binding_rec->n_mac; i++) {
    1075                 :            :         struct lport_addresses laddrs;
    1076         [ +  - ]:        492 :         if (!extract_lsp_addresses(binding_rec->mac[i], &laddrs)
    1077         [ +  + ]:        492 :             || !laddrs.n_ipv4_addrs) {
    1078                 :        490 :             continue;
    1079                 :            :         }
    1080                 :            : 
    1081                 :          2 :         add_garp(binding_rec->logical_port, ofport,
    1082                 :          2 :                  laddrs.ea, laddrs.ipv4_addrs[0].addr);
    1083                 :            : 
    1084                 :          2 :         destroy_lport_addresses(&laddrs);
    1085                 :          2 :         break;
    1086                 :            :     }
    1087                 :            : }
    1088                 :            : 
    1089                 :            : /* Remove a vif from GARP announcements. */
    1090                 :            : static void
    1091                 :          2 : send_garp_delete(const char *lport)
    1092                 :            : {
    1093                 :          2 :     struct garp_data *garp = shash_find_and_delete(&send_garp_data, lport);
    1094                 :          2 :     free(garp);
    1095                 :          2 : }
    1096                 :            : 
    1097                 :            : static long long int
    1098                 :         21 : send_garp(struct garp_data *garp, long long int current_time)
    1099                 :            : {
    1100         [ +  + ]:         21 :     if (current_time < garp->announce_time) {
    1101                 :         19 :         return garp->announce_time;
    1102                 :            :     }
    1103                 :            : 
    1104                 :            :     /* Compose a GARP request packet. */
    1105                 :            :     uint64_t packet_stub[128 / 8];
    1106                 :            :     struct dp_packet packet;
    1107                 :          2 :     dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
    1108                 :          2 :     compose_arp(&packet, ARP_OP_REQUEST, garp->ea, eth_addr_zero,
    1109                 :            :                 true, garp->ipv4, garp->ipv4);
    1110                 :            : 
    1111                 :            :     /* Compose actions.  The garp request is output on localnet ofport. */
    1112                 :            :     uint64_t ofpacts_stub[4096 / 8];
    1113                 :          2 :     struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
    1114                 :          2 :     enum ofp_version version = rconn_get_version(swconn);
    1115                 :          2 :     ofpact_put_OUTPUT(&ofpacts)->port = garp->ofport;
    1116                 :            : 
    1117                 :          8 :     struct ofputil_packet_out po = {
    1118                 :          2 :         .packet = dp_packet_data(&packet),
    1119                 :          2 :         .packet_len = dp_packet_size(&packet),
    1120                 :            :         .buffer_id = UINT32_MAX,
    1121                 :            :         .in_port = OFPP_CONTROLLER,
    1122                 :          2 :         .ofpacts = ofpacts.data,
    1123                 :          2 :         .ofpacts_len = ofpacts.size,
    1124                 :            :     };
    1125                 :          2 :     enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
    1126                 :          2 :     queue_msg(ofputil_encode_packet_out(&po, proto));
    1127                 :          2 :     dp_packet_uninit(&packet);
    1128                 :          2 :     ofpbuf_uninit(&ofpacts);
    1129                 :            : 
    1130                 :            :     /* Set the next announcement.  At most 5 announcements are sent for a
    1131                 :            :      * vif. */
    1132         [ +  - ]:          2 :     if (garp->backoff < 16) {
    1133                 :          2 :         garp->backoff *= 2;
    1134                 :          2 :         garp->announce_time = current_time + garp->backoff * 1000;
    1135                 :            :     } else {
    1136                 :          0 :         garp->announce_time = LLONG_MAX;
    1137                 :            :     }
    1138                 :         21 :     return garp->announce_time;
    1139                 :            : }
    1140                 :            : 
    1141                 :            : /* Get localnet vifs, local l3gw ports and ofport for localnet patch ports. */
    1142                 :            : static void
    1143                 :       3167 : get_localnet_vifs_l3gwports(const struct ovsrec_bridge *br_int,
    1144                 :            :                   const char *this_chassis_id,
    1145                 :            :                   const struct lport_index *lports,
    1146                 :            :                   struct hmap *local_datapaths,
    1147                 :            :                   struct sset *localnet_vifs,
    1148                 :            :                   struct simap *localnet_ofports,
    1149                 :            :                   struct sset *local_l3gw_ports)
    1150                 :            : {
    1151         [ +  + ]:      47616 :     for (int i = 0; i < br_int->n_ports; i++) {
    1152                 :      44449 :         const struct ovsrec_port *port_rec = br_int->ports[i];
    1153         [ +  + ]:      44449 :         if (!strcmp(port_rec->name, br_int->name)) {
    1154                 :       3167 :             continue;
    1155                 :            :         }
    1156                 :      41282 :         const char *chassis_id = smap_get(&port_rec->external_ids,
    1157                 :            :                                           "ovn-chassis-id");
    1158 [ +  + ][ -  + ]:      41282 :         if (chassis_id && !strcmp(chassis_id, this_chassis_id)) {
    1159                 :          0 :             continue;
    1160                 :            :         }
    1161                 :      41282 :         const char *localnet = smap_get(&port_rec->external_ids,
    1162                 :            :                                         "ovn-localnet-port");
    1163                 :      41282 :         const char *l3_gateway_port = smap_get(&port_rec->external_ids,
    1164                 :            :                                                "ovn-l3gateway-port");
    1165         [ +  + ]:      82564 :         for (int j = 0; j < port_rec->n_interfaces; j++) {
    1166                 :      41282 :             const struct ovsrec_interface *iface_rec = port_rec->interfaces[j];
    1167         [ +  + ]:      41282 :             if (!iface_rec->n_ofport) {
    1168                 :       1100 :                 continue;
    1169                 :            :             }
    1170         [ +  + ]:      40182 :             if (localnet) {
    1171                 :        327 :                 int64_t ofport = iface_rec->ofport[0];
    1172 [ +  - ][ -  + ]:        327 :                 if (ofport < 1 || ofport > ofp_to_u16(OFPP_MAX)) {
    1173                 :          0 :                     continue;
    1174                 :            :                 }
    1175                 :        327 :                 simap_put(localnet_ofports, localnet, ofport);
    1176                 :        327 :                 continue;
    1177                 :            :             }
    1178         [ +  + ]:      39855 :             if (l3_gateway_port) {
    1179                 :        643 :                 sset_add(local_l3gw_ports, l3_gateway_port);
    1180                 :        643 :                 continue;
    1181                 :            :             }
    1182                 :      39212 :             const char *iface_id = smap_get(&iface_rec->external_ids,
    1183                 :            :                                             "iface-id");
    1184         [ +  + ]:      39212 :             if (!iface_id) {
    1185                 :      26447 :                 continue;
    1186                 :            :             }
    1187                 :      12765 :             const struct sbrec_port_binding *pb
    1188                 :            :                 = lport_lookup_by_name(lports, iface_id);
    1189         [ +  + ]:      12765 :             if (!pb) {
    1190                 :        379 :                 continue;
    1191                 :            :             }
    1192                 :      12386 :             struct local_datapath *ld
    1193                 :      12386 :                 = get_local_datapath(local_datapaths,
    1194                 :      12386 :                                      pb->datapath->tunnel_key);
    1195 [ +  - ][ +  + ]:      12386 :             if (ld && ld->localnet_port) {
    1196                 :        551 :                 sset_add(localnet_vifs, iface_id);
    1197                 :            :             }
    1198                 :            :         }
    1199                 :            :     }
    1200                 :       3167 : }
    1201                 :            : 
    1202                 :            : static void
    1203                 :       3167 : get_nat_addresses_and_keys(struct sset *nat_address_keys,
    1204                 :            :                            struct sset *local_l3gw_ports,
    1205                 :            :                            const struct lport_index *lports,
    1206                 :            :                            struct shash *nat_addresses)
    1207                 :            : {
    1208                 :            :     const char *gw_port;
    1209 [ +  + ][ +  + ]:       3810 :     SSET_FOR_EACH(gw_port, local_l3gw_ports) {
                 [ +  + ]
    1210                 :        643 :         const struct sbrec_port_binding *pb = lport_lookup_by_name(lports,
    1211                 :            :                                                                    gw_port);
    1212         [ -  + ]:        643 :         if (!pb) {
    1213                 :          0 :             continue;
    1214                 :            :         }
    1215                 :        643 :         const char *nat_addresses_options = smap_get(&pb->options,
    1216                 :            :                                                      "nat-addresses");
    1217         [ +  + ]:        643 :         if (!nat_addresses_options) {
    1218                 :        617 :             continue;
    1219                 :            :         }
    1220                 :            : 
    1221                 :         26 :         struct lport_addresses *laddrs = xmalloc(sizeof *laddrs);
    1222         [ -  + ]:         26 :         if (!extract_lsp_addresses(nat_addresses_options, laddrs)) {
    1223                 :          0 :             free(laddrs);
    1224                 :          0 :             continue;
    1225                 :            :         }
    1226                 :            :         int i;
    1227         [ +  + ]:         52 :         for (i = 0; i < laddrs->n_ipv4_addrs; i++) {
    1228                 :         26 :             char *name = xasprintf("%s-%s", pb->logical_port,
    1229                 :         26 :                                             laddrs->ipv4_addrs[i].addr_s);
    1230                 :         26 :             sset_add(nat_address_keys, name);
    1231                 :         26 :             free(name);
    1232                 :            :         }
    1233                 :         26 :         shash_add(nat_addresses, pb->logical_port, laddrs);
    1234                 :            :     }
    1235                 :       3167 : }
    1236                 :            : 
    1237                 :            : static void
    1238                 :       3167 : send_garp_wait(void)
    1239                 :            : {
    1240                 :       3167 :     poll_timer_wait_until(send_garp_time);
    1241                 :       3167 : }
    1242                 :            : 
    1243                 :            : static void
    1244                 :       3167 : send_garp_run(const struct ovsrec_bridge *br_int, const char *chassis_id,
    1245                 :            :               const struct lport_index *lports,
    1246                 :            :               struct hmap *local_datapaths)
    1247                 :            : {
    1248                 :       3167 :     struct sset localnet_vifs = SSET_INITIALIZER(&localnet_vifs);
    1249                 :       3167 :     struct sset local_l3gw_ports = SSET_INITIALIZER(&local_l3gw_ports);
    1250                 :       3167 :     struct sset nat_ip_keys = SSET_INITIALIZER(&nat_ip_keys);
    1251                 :       3167 :     struct simap localnet_ofports = SIMAP_INITIALIZER(&localnet_ofports);
    1252                 :            :     struct shash nat_addresses;
    1253                 :            : 
    1254                 :       3167 :     shash_init(&nat_addresses);
    1255                 :            : 
    1256                 :       3167 :     get_localnet_vifs_l3gwports(br_int, chassis_id, lports, local_datapaths,
    1257                 :            :                       &localnet_vifs, &localnet_ofports, &local_l3gw_ports);
    1258                 :            : 
    1259                 :       3167 :     get_nat_addresses_and_keys(&nat_ip_keys, &local_l3gw_ports, lports,
    1260                 :            :                                &nat_addresses);
    1261                 :            :     /* For deleted ports and deleted nat ips, remove from send_garp_data. */
    1262                 :            :     struct shash_node *iter, *next;
    1263 [ +  + ][ -  + ]:       3187 :     SHASH_FOR_EACH_SAFE (iter, next, &send_garp_data) {
                 [ +  + ]
    1264   [ +  +  +  + ]:         30 :         if (!sset_contains(&localnet_vifs, iter->name) &&
    1265                 :         10 :             !sset_contains(&nat_ip_keys, iter->name)) {
    1266                 :          2 :             send_garp_delete(iter->name);
    1267                 :            :         }
    1268                 :            :     }
    1269                 :            : 
    1270                 :            :     /* Update send_garp_data. */
    1271                 :            :     const char *iface_id;
    1272 [ +  + ][ +  + ]:       3718 :     SSET_FOR_EACH (iface_id, &localnet_vifs) {
                 [ +  + ]
    1273                 :        551 :         const struct sbrec_port_binding *pb = lport_lookup_by_name(lports,
    1274                 :            :                                                                    iface_id);
    1275         [ +  - ]:        551 :         if (pb) {
    1276                 :        551 :             send_garp_update(pb, &localnet_ofports, local_datapaths,
    1277                 :            :                              &nat_addresses);
    1278                 :            :         }
    1279                 :            :     }
    1280                 :            : 
    1281                 :            :     /* Update send_garp_data for nat-addresses. */
    1282                 :            :     const char *gw_port;
    1283 [ +  + ][ +  + ]:       3810 :     SSET_FOR_EACH (gw_port, &local_l3gw_ports) {
                 [ +  + ]
    1284                 :        643 :         const struct sbrec_port_binding *pb = lport_lookup_by_name(lports,
    1285                 :            :                                                                 gw_port);
    1286         [ +  - ]:        643 :         if (pb) {
    1287                 :        643 :             send_garp_update(pb, &localnet_ofports, local_datapaths,
    1288                 :            :                              &nat_addresses);
    1289                 :            :         }
    1290                 :            :     }
    1291                 :            : 
    1292                 :            :     /* Send GARPs, and update the next announcement. */
    1293                 :       3167 :     long long int current_time = time_msec();
    1294                 :       3167 :     send_garp_time = LLONG_MAX;
    1295 [ +  + ][ -  + ]:       3188 :     SHASH_FOR_EACH (iter, &send_garp_data) {
    1296                 :         21 :         long long int next_announce = send_garp(iter->data, current_time);
    1297         [ +  - ]:         21 :         if (send_garp_time > next_announce) {
    1298                 :         21 :             send_garp_time = next_announce;
    1299                 :            :         }
    1300                 :            :     }
    1301                 :       3167 :     sset_destroy(&localnet_vifs);
    1302                 :       3167 :     sset_destroy(&local_l3gw_ports);
    1303                 :       3167 :     simap_destroy(&localnet_ofports);
    1304                 :            : 
    1305 [ +  + ][ -  + ]:       3193 :     SHASH_FOR_EACH_SAFE (iter, next, &nat_addresses) {
                 [ +  + ]
    1306                 :         26 :         struct lport_addresses *laddrs = iter->data;
    1307                 :         26 :         destroy_lport_addresses(laddrs);
    1308                 :         26 :         shash_delete(&nat_addresses, iter);
    1309                 :         26 :         free(laddrs);
    1310                 :            :     }
    1311                 :       3167 :     shash_destroy(&nat_addresses);
    1312                 :            : 
    1313                 :       3167 :     sset_destroy(&nat_ip_keys);
    1314                 :       3167 : }
    1315                 :            : 
    1316                 :            : static void
    1317                 :        218 : reload_metadata(struct ofpbuf *ofpacts, const struct match *md)
    1318                 :            : {
    1319                 :        218 :     enum mf_field_id md_fields[] = {
    1320                 :            : #if FLOW_N_REGS == 16
    1321                 :            :         MFF_REG0,
    1322                 :            :         MFF_REG1,
    1323                 :            :         MFF_REG2,
    1324                 :            :         MFF_REG3,
    1325                 :            :         MFF_REG4,
    1326                 :            :         MFF_REG5,
    1327                 :            :         MFF_REG6,
    1328                 :            :         MFF_REG7,
    1329                 :            :         MFF_REG8,
    1330                 :            :         MFF_REG9,
    1331                 :            :         MFF_REG10,
    1332                 :            :         MFF_REG11,
    1333                 :            :         MFF_REG12,
    1334                 :            :         MFF_REG13,
    1335                 :            :         MFF_REG14,
    1336                 :            :         MFF_REG15,
    1337                 :            : #else
    1338                 :            : #error
    1339                 :            : #endif
    1340                 :            :         MFF_METADATA,
    1341                 :            :     };
    1342         [ +  + ]:       3924 :     for (size_t i = 0; i < ARRAY_SIZE(md_fields); i++) {
    1343                 :       3706 :         const struct mf_field *field = mf_from_id(md_fields[i]);
    1344         [ +  + ]:       3706 :         if (!mf_is_all_wild(field, &md->wc)) {
    1345                 :            :             union mf_value value;
    1346                 :       1305 :             mf_get_value(field, &md->flow, &value);
    1347                 :       1305 :             ofpact_put_set_field(ofpacts, field, &value, NULL);
    1348                 :            :         }
    1349                 :            :     }
    1350                 :        218 : }
    1351                 :            : 
    1352                 :            : static void
    1353                 :          1 : pinctrl_handle_nd_na(const struct flow *ip_flow, const struct match *md,
    1354                 :            :                      struct ofpbuf *userdata)
    1355                 :            : {
    1356                 :            :     /* This action only works for IPv6 ND packets, and the switch should only
    1357                 :            :      * send us ND packets this way, but check here just to be sure. */
    1358         [ -  + ]:          1 :     if (!is_nd(ip_flow, NULL)) {
    1359                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
    1360         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "NA action on non-ND packet");
    1361                 :          0 :         return;
    1362                 :            :     }
    1363                 :            : 
    1364                 :          1 :     enum ofp_version version = rconn_get_version(swconn);
    1365                 :          1 :     enum ofputil_protocol proto = ofputil_protocol_from_ofp_version(version);
    1366                 :            : 
    1367                 :            :     uint64_t packet_stub[128 / 8];
    1368                 :            :     struct dp_packet packet;
    1369                 :          1 :     dp_packet_use_stub(&packet, packet_stub, sizeof packet_stub);
    1370                 :            : 
    1371                 :            :     /* xxx These flags are not exactly correct.  Look at section 7.2.4
    1372                 :            :      * xxx of RFC 4861.  For example, we need to set ND_RSO_ROUTER for
    1373                 :            :      * xxx router's interfaces and ND_RSO_SOLICITED only if it was
    1374                 :            :      * xxx requested. */
    1375                 :          1 :     compose_nd_na(&packet, ip_flow->dl_dst, ip_flow->dl_src,
    1376                 :            :                   &ip_flow->nd_target, &ip_flow->ipv6_src,
    1377                 :            :                   htonl(ND_RSO_SOLICITED | ND_RSO_OVERRIDE));
    1378                 :            : 
    1379                 :            :     /* Reload previous packet metadata. */
    1380                 :            :     uint64_t ofpacts_stub[4096 / 8];
    1381                 :          1 :     struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub);
    1382                 :          1 :     reload_metadata(&ofpacts, md);
    1383                 :            : 
    1384                 :          1 :     enum ofperr error = ofpacts_pull_openflow_actions(userdata, userdata->size,
    1385                 :            :                                                       version, &ofpacts);
    1386         [ -  + ]:          1 :     if (error) {
    1387                 :            :         static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
    1388         [ #  # ]:          0 :         VLOG_WARN_RL(&rl, "failed to parse actions for 'na' (%s)",
    1389                 :            :                      ofperr_to_string(error));
    1390                 :          0 :         goto exit;
    1391                 :            :     }
    1392                 :            : 
    1393                 :          4 :     struct ofputil_packet_out po = {
    1394                 :          1 :         .packet = dp_packet_data(&packet),
    1395                 :          1 :         .packet_len = dp_packet_size(&packet),
    1396                 :            :         .buffer_id = UINT32_MAX,
    1397                 :            :         .in_port = OFPP_CONTROLLER,
    1398                 :          1 :         .ofpacts = ofpacts.data,
    1399                 :          1 :         .ofpacts_len = ofpacts.size,
    1400                 :            :     };
    1401                 :            : 
    1402                 :          1 :     queue_msg(ofputil_encode_packet_out(&po, proto));
    1403                 :            : 
    1404                 :            : exit:
    1405                 :          1 :     dp_packet_uninit(&packet);
    1406                 :          1 :     ofpbuf_uninit(&ofpacts);
    1407                 :            : }

Generated by: LCOV version 1.12